原题链接
注意:
- 以新审旧.
- 线段树部分不要出错.
- 点编号向线段树下标的映射.
代码如下:
#include <cstdio>
#include <cctype>
#include <cstring>
#include <cmath>
#include <iostream>
using namespace std;
#define ll long long
inline ll read() {
ll x = 0, f = 0; char ch = getchar();
while (!isdigit(ch)) f = ch == '-', ch = getchar();
while (isdigit(ch)) x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar();
return f ? -x : x;
}
void print(int x) {
if (x < 0) x = -x, putchar('-');
if (x < 10) putchar(x + '0');
else {
print(x / 10);
putchar(x % 10 + '0');
}
}
const int N = 1e5 + 5;
int n, m, rt, vt[N]; ll p;
int head[N], nex[N << 1], ver[N << 1], tot;
int siz[N], dep[N], fa[N], ms[N];
int f1[N], f2[N], top[N], num;
inline void AddMod(ll &x, ll y) { x = (x + y) % p; }
void Addedge(int x, int y) {
ver[++tot] = y;
nex[tot] = head[x];
head[x] = tot;
}
void dfs1(int x, int fat) {
fa[x] = fat; siz[x] = 1;
dep[x] = dep[fat] + 1;
for (int i = head[x]; i; i = nex[i]) {
int y = ver[i];
if (y == fat) continue;
dfs1(y, x);
siz[x] += siz[y];
if (siz[y] > siz[ms[x]]) ms[x] = y;
}
}
void dfs2(int x, int topx) {
top[x] = topx;
f1[x] = ++num; f2[num] = x;
if (!ms[x]) return;
dfs2(ms[x], topx);
for (int i = head[x]; i; i = nex[i]) {
int y = ver[i];
if (y != ms[x] && y != fa[x]) dfs2(y, y);
}
}
struct Node {
int l, r; ll val, tag;
};
Node nd[N << 2];
void update(int x) {
nd[x].val = (nd[x << 1].val + nd[x << 1 | 1].val) % p;
}
void pushdown(int x) {
if (nd[x].tag) {
AddMod(nd[x << 1].tag, nd[x].tag);
AddMod(nd[x << 1 | 1].tag, nd[x].tag);
AddMod(nd[x << 1].val, nd[x].tag * (nd[x << 1].r - nd[x << 1].l + 1));
AddMod(nd[x << 1 | 1].val, nd[x].tag * (nd[x << 1 | 1].r - nd[x << 1 | 1].l + 1));
nd[x].tag = 0;
}
}
void Build_tree(int now, int l, int r) {
nd[now].l = l; nd[now].r = r;
if (l == r) { nd[now].val = 1ll * vt[f2[l]]; return; }
int mid = (l + r) >> 1;
Build_tree(now << 1, l, mid); Build_tree(now << 1 | 1, mid + 1, r);
update(now);
}
ll Ask(int now, int l, int r) {
if (nd[now].l == l && nd[now].r == r) return nd[now].val;
pushdown(now);
int mid = (nd[now].l + nd[now].r) >> 1;
if (r <= mid) return Ask(now << 1, l, r);
else if (l > mid) return Ask(now << 1 | 1, l, r);
else return (Ask(now << 1, l, mid) + Ask(now << 1 | 1, mid + 1, r)) % p;
}
void Add(int now, int l, int r, ll k) {
if (nd[now].l == l && nd[now].r == r) { AddMod(nd[now].tag, k); AddMod(nd[now].val, k * (r - l + 1)); return; }
pushdown(now);
int mid = (nd[now].l + nd[now].r) >> 1;
if (r <= mid) Add(now << 1, l, r, k);
else if (l > mid) Add(now << 1 | 1, l, r, k);
else Add(now << 1, l, mid, k), Add(now << 1 | 1, mid + 1, r, k);
update(now);
}
void Adddist(int x, int y, ll z) {
while (top[x] != top[y]) {
if (dep[top[x]] > dep[top[y]]) swap(x, y);
Add(1, f1[top[y]], f1[y], z); y = fa[top[y]];
}
if (dep[x] > dep[y]) swap(x, y);
Add(1, f1[x], f1[y], z);
}
ll Askdist(int x, int y) {
ll res = 0;
while (top[x] != top[y]) {
if (dep[top[x]] > dep[top[y]]) swap(x, y);
AddMod(res, Ask(1, f1[top[y]], f1[y])); y = fa[top[y]];
}
if (dep[x] > dep[y]) swap(x, y);
AddMod(res, Ask(1, f1[x], f1[y]));
return res;
}
int main() {
n = read(); m = read(); rt = read(); p = read();
for (int i = 1; i <= n; ++i) vt[i] = read() % p;
for (int i = 1; i < n; ++i) { int uu = read(), vv = read(); Addedge(uu, vv); Addedge(vv, uu); }
dfs1(rt, 0); dfs2(rt, rt);
Build_tree(1, 1, n);
while (m--) {
int opt = read();
if (opt == 1) { int x = read(), y = read(); ll z = read(); Adddist(x, y, z); }
else if (opt == 2) { int x = read(), y = read(); print(Askdist(x, y)); putchar('\n');}
else if (opt == 3) { int x = read(); ll z = read(); Add(1, f1[x], f1[x] + siz[x] - 1, z); }
else { int x = read(); print(Ask(1, f1[x], f1[x] + siz[x] - 1)); putchar('\n'); }
}
return 0;
}