洛谷P3384【模板】树链剖分·第一个树剖祭
题目描述
如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作:
操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z
操作2: 格式: 2 x y 表示求树从x到y结点最短路径上所有节点的值之和
操作3: 格式: 3 x z 表示将以x为根节点的子树内所有节点值都加上z
操作4: 格式: 4 x 表示求以x为根节点的子树内所有节点值之和
输入输出格式
输入格式:
第一行包含4个正整数N、M、R、P,分别表示树的结点个数、操作个数、根节点序号和取模数(即所有的输出结果均对此取模)。
接下来一行包含N个非负整数,分别依次表示各个节点上初始的数值。
接下来N-1行每行包含两个整数x、y,表示点x和点y之间连有一条边(保证无环且连通)
接下来M行每行包含若干个正整数,每行表示一个操作,格式如下:
操作1: 1 x y z
操作2: 2 x y
操作3: 3 x z
操作4: 4 x
输出格式:
输出包含若干行,分别依次表示每个操作2或操作4所得的结果(对P取模)
代码:(感觉自己写的有点长```>_<```······)
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int MAX = 100005; 4 typedef struct Node{ 5 long long val, tag; 6 int l, r; 7 Node *rson, *lson; 8 int len() {return r - l;} 9 int mid() {return (l + r) >> 1;} 10 Node(): rson(NULL), lson(NULL), l(0), r(0), val(0), tag(0){} 11 }node, *pointer; 12 13 int mod; 14 15 class Segment_Tree 16 { 17 public: 18 pointer rt = new Node(); 19 long long a[MAX]; 20 21 void PushUp(pointer rt) 22 { 23 rt->val = rt->rson->val + rt->lson->val; 24 } 25 26 void PushDown(pointer rt) 27 { 28 if(rt->tag) 29 { 30 rt->lson->tag += rt->tag; 31 rt->rson->tag += rt->tag; 32 rt->lson->val += rt->tag * rt->lson->len(); 33 rt->rson->val += rt->tag * rt->rson->len(); 34 rt->tag = 0; 35 } 36 } 37 38 void Build(pointer rt,int l, int r) 39 { 40 rt->l = l; 41 rt->r = r; 42 if(l + 1 == r) 43 { 44 rt->val = a[l]; 45 //rt->pos = l; 46 rt->rson = NULL; 47 rt->lson = NULL; 48 return ; 49 } 50 rt->rson = new Node(); 51 rt->lson = new Node(); 52 Build(rt->lson, l, rt->mid()); 53 Build(rt->rson, rt->mid(), r); 54 PushUp(rt); 55 } 56 57 void UpData(pointer rt, int L, int R, int k) 58 { 59 if(L <= rt->l && rt->r <= R) 60 { 61 rt->val += k * rt->len(); 62 rt->tag += k; 63 } 64 else 65 { 66 if(rt->tag != 0) PushDown(rt); 67 if(L < rt->mid()) UpData(rt->lson, L, R, k); 68 if(R > rt->mid()) UpData(rt->rson, L, R, k); 69 PushUp(rt); 70 } 71 } 72 73 long long Query(pointer rt, int L, int R) 74 { 75 if(L <= rt->l && rt->r <= R) return rt->val; 76 else 77 { 78 if(rt->tag != 0) PushDown(rt); 79 long long ret = 0; 80 if(L < rt->mid()) ret += Query(rt->lson, L, R); 81 if(R > rt->mid()) ret += Query(rt->rson, L, R); 82 return ret; 83 } 84 } 85 }; 86 87 class Tree_Chain_Division 88 { 89 private: 90 int Head[MAX], Next[MAX << 1], To[MAX << 1], edgenum = 0; 91 int size[MAX], Hson[MAX], Father[MAX], Deep[MAX], pos[MAX]; 92 int tid[MAX], ti = 0, top[MAX]; 93 Segment_Tree tree; 94 95 void First_Dfs(int u, int fa) 96 { 97 size[u] = 1, Father[u] = fa; 98 for(int i = Head[u]; i != -1; i = Next[i]) 99 { 100 int v = To[i]; 101 if(v == fa) continue; 102 Deep[v] = Deep[u] + 1; 103 First_Dfs(v, u); 104 size[u] += size[v]; 105 if(size[v] > size[Hson[u]] || Hson[u] == 0) Hson[u] = v; 106 } 107 return; 108 } 109 110 void Second_Dfs(int u, int anc) 111 { 112 top[u] = anc, tid[u] = ++ti, pos[ti] = u; 113 if(Hson[u] == 0) return; 114 Second_Dfs(Hson[u], anc); 115 for(int i = Head[u]; i != -1; i = Next[i]) 116 { 117 int v = To[i]; 118 if(Father[u] == v || Hson[u] == v) continue; 119 Second_Dfs(v, v); 120 } 121 return ; 122 } 123 124 public: 125 int a[MAX]; 126 127 void init() 128 { 129 memset(Head, -1, sizeof(Head)); 130 } 131 132 void Add_edge(int from, int to) 133 { 134 Next[++ edgenum] = Head[from]; 135 To[edgenum] = to; 136 Head[from] = edgenum; 137 } 138 139 void Chain_Division(int root, int n) 140 { 141 Deep[root] = 1; 142 First_Dfs(root, 0); 143 Second_Dfs(root, root); 144 for(int i = 1; i <= n; ++ i) tree.a[i] = a[pos[i]]; 145 tree.Build(tree.rt, 1, n + 1); 146 return; 147 } 148 149 int Get_LCA(int x, int y) 150 { 151 int Father_x = top[x], Father_y = top[y]; 152 for(;Father_x != Father_y;) 153 { 154 if(Deep[Father_x] < Deep[Father_y]) 155 swap(Father_y, Father_x), swap(x, y); 156 x = Father[Father_x], Father_x = top[x]; 157 } 158 return Deep[x] < Deep[y] ? x : y; 159 } 160 161 void Chai_Add(int x, int y, int w) //x y z 表示将树从x到y结点最短路径上所有节点的值都加上w 162 { 163 int Father_x = top[x], Father_y = top[y]; 164 for(;Father_x != Father_y;) 165 { 166 if(Deep[Father_x] < Deep[Father_y]) 167 swap(Father_y, Father_x), swap(x, y); 168 tree.UpData(tree.rt, tid[Father_x], tid[x] + 1, w); 169 x = Father[Father_x], Father_x = top[x]; 170 } 171 if(Deep[x] < Deep[y]) swap(x, y); 172 tree.UpData(tree.rt, tid[y], tid[x] + 1, w); 173 return ; 174 } 175 176 long long Chai_Query(int x, int y) //x y 表示求树从x到y结点最短路径上所有节点的值之和 177 { 178 long long ans = 0; 179 int Father_x = top[x], Father_y = top[y]; 180 for(;Father_x != Father_y;) 181 { 182 if(Deep[Father_x] < Deep[Father_y]) 183 swap(Father_y, Father_x), swap(x, y); 184 ans = (ans + tree.Query(tree.rt, tid[Father_x], tid[x] + 1)) % mod; 185 x = Father[Father_x], Father_x = top[x]; 186 } 187 if(Deep[x] < Deep[y]) swap(x, y); 188 ans = (ans + tree.Query(tree.rt, tid[y], tid[x] + 1)) % mod; 189 return ans; 190 } 191 192 void Tree_Add(int x, int w) //x w 表示将以x为根节点的子树内所有节点值都加上w 193 { 194 tree.UpData(tree.rt, tid[x], tid[x] + size[x], w); 195 return; 196 } 197 198 long long Tree_Query(int x) //x 表示求以x为根节点的子树内所有节点值之和 199 { 200 return tree.Query(tree.rt, tid[x], tid[x] + size[x]) % mod; 201 } 202 }; 203 204 inline int Qread() 205 { 206 int x = 0, w = 0; char ch = getchar(); 207 for(;!isdigit(ch);w |= (ch == '-'), ch = getchar()); 208 for(;isdigit(ch); x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar()); 209 return w ? -x : x; 210 } 211 212 Tree_Chain_Division division; 213 int main() 214 { 215 // freopen("sp.in", "r", stdin); 216 // freopen("sp.out", "w", stdout); 217 218 int x, y, opt, z, n = Qread(), m = Qread(), root = Qread(); mod = Qread(); 219 for(int i = 1; i <= n; ++ i) division.a[i] = Qread(); 220 division.init(); 221 for(int i = 1; i < n; ++ i) 222 { 223 x = Qread(), y = Qread(); 224 division.Add_edge(x, y), division.Add_edge(y, x); 225 } 226 division.Chain_Division(root, n); 227 for(int i = 1; i <= m; ++ i) 228 { 229 opt = Qread(); 230 switch(opt) 231 { 232 case 1: x = Qread(), y = Qread(), z = Qread(); division.Chai_Add(x, y, z); break; 233 case 2: x = Qread(), y = Qread(); printf("%lld ", division.Chai_Query(x, y)); break; 234 case 3: x = Qread(), y = Qread(); division.Tree_Add(x, y); break; 235 case 4: x = Qread(); printf("%lld ", division.Tree_Query(x)); break; 236 } 237 } 238 return 0; 239 }