对于这个树剖吧。。。一开始不打算学的。。。但是貌似挺有用的,于是乎下狠心学了一哈。本蒟蒻初学树剖可能理解不太透彻,如有不对之处还请各位巨佬指正
先来一个树剖的了解 IvanovCraft的博客
首先我们需要了解一下树链剖分可以用来干什么:
1.可以求树上差分,LCA(时间复杂度会小一些)
2.最重要的是可以修改树上的边权或者点权(比如本题)
剩下的目前本蒟蒻还too vegetable,所以对其理解不够深,许多用法可能以后会更新
貌似大佬们看看上面博客就好了
Code:

1 #include <bits/stdc++.h> 2 #define ls x << 1 3 #define rs x << 1 | 1 4 using namespace std; 5 const int N = 200001; 6 int n, m, r, p; 7 int tot, head[N];//邻接链表存边 8 struct edge{ 9 int net, v; 10 }e[N]; 11 int a[N * 4], v[N * 4]; 12 int cnt, w[N], wt[N], son[N], d[N], siz[N], fa[N], id[N], top[N]; 13 //w[]存读入的点,wt[]存dfs遍历后的点,son[]存每个节点的重儿子,d[]存每个点的深度,size[]存以当前节点为根节点的子树的大小 14 //fa[]存每个节点的父亲节点,id[]存每个点的dfs序,top[]存当前节点所在重链的根节点 15 void add(int u, int v) { 16 e[++tot].net = head[u]; 17 e[tot].v = v; 18 head[u] = tot; 19 } 20 void push(int x, int l) {//更新懒标 21 v[ls] += v[x]; 22 v[rs] += v[x]; 23 a[ls] += v[x] * (l - l / 2);//这里上下互换也可以,只是为了将这条链分成两部分。 24 //又考虑到长度不可能全是偶数,所以一个上取整,另一个下取整。 25 a[rs] += v[x] * (l / 2); 26 a[ls] %= p; 27 a[rs] %= p; 28 v[x] = 0; 29 } 30 void build(int x, int l, int r) { 31 if (l == r) { 32 a[x] = wt[l];//wt[]数组存的是dfs遍历后的点 33 a[x] %= p; 34 return; 35 } 36 int mid = (l + r) / 2; 37 build(ls, l, mid); 38 build(rs, mid + 1, r); 39 a[x] = (a[ls] + a[rs]) % p; 40 } 41 int query(int x, int l, int r, int L, int R) {//线段树维护和 42 int res = 0; 43 if (L <= l && r <= R) { 44 res += a[x]; 45 res %= p; 46 return res; 47 } 48 if (v[x]) { 49 push(x, r - l + 1); 50 } 51 int mid = (l + r) / 2; 52 if (L <= mid) { 53 res += query(ls, l, mid, L, R); 54 } 55 if (R > mid) { 56 res += query(rs, mid + 1, r, L, R); 57 } 58 return res % p; 59 } 60 void change(int x, int l, int r, int L, int R, int k) {//十分正常的修改 61 if (L <= l && r <= R) { 62 v[x] += k; 63 a[x] += k * (r - l + 1); 64 a[x] %= p; 65 return; 66 } 67 if (v[x]) { 68 push(x, r - l + 1); 69 } 70 int mid = (l + r) / 2; 71 if (L <= mid) { 72 change(ls, l, mid, L, R, k); 73 } 74 if(R > mid) { 75 change(rs, mid + 1, r, L, R, k); 76 } 77 a[x] = (a[ls] + a[rs]) % p; 78 } 79 void Qchange(int x, int y, int k) { 80 k %= p; 81 while (top[x] != top[y]) {//当这两个点不在同一条重链上 82 if (d[top[x]] < d[top[y]]) {//调整深度,让x变成更深的那一个 83 swap(x, y); 84 } 85 change(1, 1, n, id[top[x]], id[x], k);//修改 86 x = fa[top[x]];//每次结束后都要跳到父亲那里 87 } 88 if (d[x] > d[y]) {//当两节点在一条重链上但不是同一节点时 89 //调整深度 90 swap(x, y); 91 } 92 change(1, 1, n, id[x], id[y], k);//在最后的距离上进行修改 93 } 94 int Qquery(int x, int y) { 95 int ans = 0; 96 while (top[x] != top[y]) {//当这两个点不在同一条重链上 97 if (d[top[x]] < d[top[y]]) {//调整深度,让x变成更深的那一个 98 swap(x, y); 99 } 100 ans += query(1, 1, n, id[top[x]], id[x]);//累加答案 101 ans %= p; 102 x = fa[top[x]];//每次结束后都要跳到父亲那里 103 } 104 if (d[x] > d[y]) { 105 swap(x, y); 106 } 107 ans += query(1, 1, n, id[x], id[y]); 108 return ans % p; 109 } 110 void Schange(int x, int k) { 111 change(1, 1, n, id[x], id[x] + siz[x] - 1, k); 112 //因为要修改以x为根节点的子树,所以边界就是 id[x] 到 id[x] + siz[x] - 1 113 } 114 int Squery(int x) { 115 return query(1, 1, n, id[x], id[x] + siz[x] - 1);//同上 116 } 117 void dfs1(int x, int f, int deep) {//核心函数1 118 d[x] = deep;//深度 119 fa[x] = f;//父亲节点 120 siz[x] = 1;//当前节点大小为1 121 int maxson = -1; 122 for (int i = head[x]; i; i = e[i].net) {//枚举所有出边 123 int to = e[i].v; 124 if (to == f) {//肯定不能回到自己父亲吧~ 125 continue; 126 } 127 dfs1(to, x, deep + 1);//继续dfs 128 siz[x] += siz[to];//大小累加 129 if (siz[to] > maxson) {//跟新重儿子 130 son[x] = to; 131 maxson = siz[to]; 132 } 133 } 134 } 135 void dfs2(int x, int topf) {//核心函数2 136 id[x] = ++cnt;//按照重链dfs来储存新的dfs序 137 wt[cnt] = w[x];//储存下来 138 top[x] = topf;//因为在同一重链上,直接赋值 139 if (!son[x]) {//如果当前节点没有重儿子就停止 140 return; 141 } 142 dfs2(son[x], topf);//优先重儿子进行深搜 143 for (int i = head[x]; i; i = e[i].net) { 144 int to = e[i].v; 145 if (to == fa[x] || to == son[x]) {//如果是自己的父亲或者是重儿子就跳过 146 continue; 147 } 148 dfs2(to, to);//因为轻儿子不在重链上,所以它的top就是自己 149 } 150 } 151 int main() { 152 scanf("%d%d%d%d", &n, &m, &r, &p); 153 for (int i = 1; i <= n; i++) { 154 scanf("%d", &w[i]); 155 } 156 for (int i = 1; i < n; i++) { 157 int u, v; 158 scanf("%d%d", &u, &v); 159 add(u, v); 160 add(v, u); 161 } 162 dfs1(r, 0, 1); 163 dfs2(r, r); 164 build(1, 1, n); 165 for (int i = 1; i <= m; i++) { 166 int o, x, y, z; 167 scanf("%d", &o); 168 if (o == 1) { 169 scanf("%d%d%d", &x, &y, &z); 170 Qchange(x, y, z); 171 } else if (o == 2) { 172 scanf("%d%d", &x, &y); 173 printf("%d ", Qquery(x, y)); 174 } else if (o == 3) { 175 scanf("%d%d", &x, &z); 176 Schange(x, z); 177 } else { 178 scanf("%d", &x); 179 printf("%d ", Squery(x)); 180 } 181 } 182 return 0; 183 }