buowen123 @ 2023-11-15 22:03:16
//dep, fa, siz, son, 新编号id, 新的值a,
#include <iostream>
#define endl '\n'
using namespace std;
typedef long long ll;
const int N = 1e5 + 5;
int n, m, r, tot, head[N];
int cnt, dep[N], fa[N], siz[N], son[N], id[N], top[N];
ll p, w[N], a[N];
struct edge {
int to, nxt;
} e[N * 2];
void add (int u, int v) {
++tot;
e[tot].nxt = head[u];
e[tot].to = v;
head[u] = tot;
}
namespace Stree {
struct Tree {
int l, r;
ll val, laz;
void update (ll v) {
laz = (laz + v) % p;
val = (val + (r - l + 1) * v) % p;
}
} tree[4 * N];
void pushup (int t) {
tree[t].val = (tree[t << 1].val + tree[t << 1 | 1].val) % p;
}
void pushdown (int t) {
ll lazy = tree[t].laz;
if (lazy == 0) {
return ;
}
tree[t << 1].update (lazy);
tree[t << 1 | 1].update (lazy);
tree[t].laz = 0;
}
void build (int t, int l, int r) {
tree[t].l = l;
tree[t].r = r;
if (l == r) {
tree[t].val = a[l];
return ;
}
int mid = l + r >> 1;
build (t << 1, l, mid);
build (t << 1 | 1, mid + 1, r);
pushup (t);
}
void update (int t, int l, int r, ll v) {
int ql = tree[t].l, qr = tree[t].r;
if (l <= ql && qr <= r) {
tree[t].update (v);
return ;
}
pushdown (t);
int mid = ql + qr >> 1;
if (mid >= l) {
update (t << 1, l, r, v);
}
if (mid < r) {
update (t << 1 | 1, l, r, v);
}
pushup (t);
}
ll query (int t, int l, int r) {
int ql = tree[t].l, qr = tree[t].r;
if (l <= ql && qr <= r) {
return tree[t].val;
}
pushdown (t);
int mid = ql + qr >> 1;
ll res = 0;
if (mid >= l) {
res = (res + query (t << 1, l, r)) % p;
}
if (mid < r) {
res = (res + query (t << 1 | 1, l, r)) % p;
}
pushup (t);
return res;
}
}
void dfs1 (int u, int f) {
fa[u] = f;
dep[u] = dep[f] + 1;
siz[u] = 1;
int maxval = 0;
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
if (v == f) {
continue;
}
dfs1 (v, u);
siz[u] += siz[v];
if (siz[v] > maxval) {
maxval = siz[v];
son[u] = v;
}
}
}
void dfs2 (int u, int tp) {
++cnt;
id[u] = cnt;
a[cnt] = w[u];
top[u] = tp;
if (son[u] == 0) {
return ;
}
dfs2 (son[u], tp);
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
if (v == fa[u] || v == son[u]) {
continue;
}
dfs2 (v, v);
}
}
void pathupd (int x, int y, ll z) {
while (top[x] != top[y]) {
if (dep[top[x]] < dep[top[y]]) {
swap (x, y);
}
Stree::update (1, id[top[x]], id[x], z);
x = fa[top[x]];
}
if (top[x] > top[y]) {
swap (x, y);
}
Stree::update (1, id[x], id[y], z);
}
ll pathque (int x, int y) {
ll res = 0;
while (top[x] != top[y]) {
if (dep[top[x]] < dep[top[y]]) {
swap (x, y);
}
res = (res + Stree::query (1, id[top[x]], id[x])) % p;
x = fa[top[x]];
}
if (top[x] > top[y]) {
swap (x, y);
}
res = (res + Stree::query (1, id[x], id[y])) % p;
return res;
}
void treeupd (int x, ll z) {
Stree::update (1, id[x], id[x] + siz[x] - 1, z);
}
ll treeque (int x) {
return Stree::query (1, id[x], id[x] + siz[x] - 1);
}
int main () {
cin >> n >> m >> r >> p;
for (int i = 1; i <= n; ++i) {
cin >> w[i];
}
for (int i = 1; i <= n - 1; ++i) {
int u, v;
cin >> u >> v;
add (u, v);
add (v, u);
}
dfs1 (r, 0);
dfs2 (r, r);
Stree::build (1, 1, n);
for (int i = 1; i <= m; ++i) {
int opt, x, y;
ll z;
cin >> opt;
switch (opt) {
case 1: { cin >> x >> y >> z; pathupd (x, y, z); break; }
case 2: { cin >> x >> y; cout << pathque (x, y) % p << endl; break; }
case 3: { cin >> x >> z; treeupd (x, z); break; }
case 4: { cin >> x; cout << treeque (x) % p << endl; break; }
}
}
return 0;
}
by buowen123 @ 2023-11-15 22:08:06
才发现 if (top[x] > top[y])
应当改为 if (dep[x] > dep[y])
,此帖结