jimmy916 @ 2024-08-09 13:31:21
#include <iostream>
#include <cstdio>
#include <vector>
#define ll long long
#define ls(x) (x<<1)
#define rs(x) (x<<1)|1
using namespace std;
const int N = 2 * 1e5 + 1;
struct tree {
ll l, r;
ll val;
ll lazy;
};
ll n, m, root, p;
ll a[N], fa[N], son[N], siz[N], top[N], dfn[N], rnk[N], dep[N];
// a:权值 fa:父亲 son:重子节点 siz:子树大小 top:链顶 dfn:DFS序 rnk:DFS序对应编号 dep:深度
ll cnt;
vector<ll> g[N];
tree t[N << 2]; // 线段树
void pushup(ll x) {
t[x].val = (t[ls(x)].val + t[rs(x)].val);
return;
}
void pushdown(ll x) {
if (t[x].l == t[x].r) {
t[x].lazy = 0;
return;
}
t[ls(x)].val += (t[ls(x)].r - t[ls(x)].l + 1) * t[x].lazy;
t[rs(x)].val += (t[rs(x)].r - t[rs(x)].l + 1) * t[x].lazy;
t[ls(x)].lazy += t[x].lazy, t[rs(x)].lazy += t[x].lazy;
return;
}
void build(ll l, ll r, ll x) {
t[x].l = l, t[x].r = r;
if (l == r) {
t[x].val = a[rnk[l]];
return;
}
int mid = (l + r) >> 1;
build(l, mid, ls(x)), build(mid + 1, r, rs(x));
pushup(x);
return;
}
void add(ll l, ll r, ll k, ll x) {
if (t[x].l > r || t[x].r < l)
return;
if (l <= t[x].l && t[x].r <= r) {
t[x].val += (t[x].r - t[x].l + 1) * k;
t[x].lazy += k;
return;
}
if (t[x].lazy)
pushdown(x);
add(l, r, k, ls(x)), add(l, r, k, rs(x));
pushup(x);
return;
}
ll ask(ll l, ll r, ll x) {
if (t[x].l > r || t[x].r < l)
return 0;
if (l <= t[x].l && t[x].r <= r)
return t[x].val;
if (t[x].lazy)
pushdown(x);
ll sum = (ask(l, r, ls(x)) + ask(l, r, rs(x)));
pushup(x);
return sum;
}
// 以上是线段树
void dfs1(ll now, ll fath) { // 求fa, dep, siz, son
fa[now] = fath, dep[now] = dep[fath] + 1;
siz[now] = 1;
for (ll i = 0; i < (ll)g[now].size(); i ++ ) {
ll v = g[now][i];
if (v == fath)
continue;
dfs1(v, now);
siz[now] += siz[v];
if (siz[v] > siz[son[now]])
son[now] = v;
}
return;
}
void dfs2(ll now, ll anc) { // 求top, dfn, rnk
top[now] = anc;
dfn[now] = ++ cnt;
rnk[cnt] = now;
if (!son[now])
return;
dfs2(son[now], anc);
for (ll i = 0; i < (ll)g[now].size(); i ++ ) {
ll v = g[now][i];
if (v != fa[now] && v != son[now])
dfs2(v, v);
}
return;
}
ll ask_range(ll x, ll y) { // 询问链
ll sum = 0;
while (top[x] != top[y]) {
if (dep[top[x]] < dep[top[y]])
swap(x, y);
sum += ask(dfn[top[x]], dfn[x], 1);
x = fa[top[x]];
}
return sum + ask(min(dfn[x], dfn[y]), dfn[max(dfn[x], dfn[y])], 1);
}
void update_range(ll x, ll y, ll k) { // 更新链
while (top[x] != top[y]) {
if (dep[top[x]] < dep[top[y]])
swap(x, y);
add(dfn[top[x]], dfn[x], k, 1);
x = fa[top[x]];
}
add(min(dfn[x], dfn[y]), dfn[max(dfn[x], dfn[y])], k, 1);
return;
}
ll ask_son(ll x) { // 询问子树
return ask(dfn[x], dfn[x] + siz[x] - 1, 1);
}
void update_son(ll x, ll k) { // 更新子树
add(dfn[x], dfn[x] + siz[x] - 1, k, 1);
return;
}
int main() {
scanf("%lld%lld%lld%lld", &n, &m, &root, &p);
for (ll i = 1; i <= n; i ++ )
scanf("%lld", &a[i]);
for (ll i = 1; i < n; i ++ ) {
ll x, y;
scanf("%lld%lld", &x, &y);
g[x].push_back(y), g[y].push_back(x);
}
dfs1(root, 0);
dfs2(root, root);
build(1, n, 1);
while (m -- ) {
int op;
cin >> op;
if (op == 1) {
ll x, y, k;
scanf("%lld%lld%lld", &x, &y, &k);
update_range(x, y, k);
} else if (op == 2) {
ll x, y;
scanf("%lld%lld", &x, &y);
printf("%lld\n", ask_range(x, y) % p);
} else if (op == 3) {
ll x, k;
scanf("%lld%lld", &x, &k);
update_son(x, k);
} else {
ll x;
scanf("%lld", &x);
printf("%lld\n", ask_son(x) % p);
}
}
return 0;
}
by UMS2 @ 2024-08-09 14:06:19
@jimmy916 pushdown
内没有清零自己的懒标记。
by jimmy916 @ 2024-08-09 14:08:58
@UMS2 自己发现了,已A,不过还是谢谢