1、hdu 3966 Aragorn's Story
题意:敌人有n个帐篷,每个帐篷有初始人数,两两之间只有一条路径。现在进行q次操作,可以把c1到c2路径上的所有帐篷人数都加上或减去一个值,或者询问某个帐篷当前人数。
思路:树链剖分模板题,线段树,点权,区间更新,单点查询。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<iostream> 2 #include<cstring> 3 using namespace std; 4 const int maxn = 50000 + 10; 5 6 /*-------树链剖分·启-------*/ 7 8 int siz[maxn];//size[i]:以i为根的子树结点个数 9 int top[maxn];//保存结点i所在链的顶端结点 10 int son[maxn];//保存i的重儿子 11 int dep[maxn];//保存结点i的层次(深度) 12 int father[maxn];//保存结点i的父亲结点 13 int nid[maxn];//保存树节点剖分后的对应新编号 14 int oid[maxn];//保存新编号对应在剖分的树中的结点(与nid相反) 15 int cnt = 0;//重编号 16 int val[maxn];//结点值 17 struct EDGE 18 { 19 int from, to, next; 20 EDGE(int ff = 0, int tt = 0, int nn = 0) :from(ff), to(tt), next(nn) {} 21 }edge[maxn * 2]; 22 int Head[maxn], totedge = 0; 23 void addEdge(int from, int to) 24 { 25 edge[totedge] = EDGE(from, to, Head[from]); 26 Head[from] = totedge++; 27 edge[totedge] = EDGE(to, from, Head[to]); 28 Head[to] = totedge++; 29 } 30 void INIT() 31 { 32 memset(Head, -1, sizeof(Head)); 33 totedge = 0; 34 35 memset(son, -1, sizeof(son)); 36 memset(siz, 0, sizeof(siz)); 37 memset(father, 0, sizeof(father)); 38 memset(top, 0, sizeof(top)); 39 memset(dep, 0, sizeof(dep)); 40 cnt = 0; 41 } 42 43 void dfs1(int u, int fa, int layer) 44 { 45 dep[u] = layer; 46 father[u] = fa; 47 siz[u] = 1; 48 for (int i = Head[u]; i != -1; i = edge[i].next) 49 { 50 int v = edge[i].to; 51 if (v != fa) 52 { 53 dfs1(v, u, layer + 1); 54 siz[u] += siz[v]; 55 if (son[u] == -1 || siz[v] > siz[son[u]]) 56 { 57 son[u] = v; 58 } 59 } 60 } 61 } 62 63 void dfs2(int u, int Hson) 64 {//Hson,重儿子 65 top[u] = Hson; 66 nid[u] = ++cnt; 67 oid[cnt] = u; 68 if (son[u] == -1) return; 69 dfs2(son[u], Hson);//先将当前重链重编号 70 for (int i = Head[u]; i != -1; i = edge[i].next) 71 {//对不在重链上的点,自己作为子树的重链起点重编号 72 int v = edge[i].to; 73 if (v != son[u] && v != father[u]) dfs2(v, v); 74 } 75 } 76 /*-------线段树·启————*/ 77 struct treenode 78 { 79 int l, r; 80 long long v, tmp; 81 treenode(int ll = 0, int rr = 0, long long vv = 0, long long tt = 0) :l(ll), r(rr), v(vv), tmp(tt) {} 82 }tree[maxn * 4]; 83 84 void BuildTree(int root, int l, int r) 85 { 86 tree[root].l = l, tree[root].r = r; 87 tree[root].tmp = 0; 88 if (l == r) 89 { 90 tree[root].v = val[oid[l]]; 91 return; 92 } 93 int mid = (l + r) / 2; 94 BuildTree(root * 2, l, mid); 95 BuildTree(root * 2 + 1, mid + 1, r); 96 tree[root].v = tree[root * 2].v + tree[root * 2 + 1].v; 97 } 98 void Pushdown(int root) 99 { 100 int lson = root * 2, rson = root * 2 + 1; 101 if (tree[root].tmp) 102 { 103 tree[lson].v += (tree[lson].r - tree[lson].l + 1)*tree[root].tmp; 104 tree[rson].v += (tree[rson].r - tree[rson].l + 1)*tree[root].tmp; 105 tree[lson].tmp += tree[root].tmp; 106 tree[rson].tmp += tree[root].tmp; 107 tree[root].tmp = 0; 108 } 109 } 110 void PushUp(int root) 111 { 112 tree[root].v = tree[root * 2].v + tree[root * 2 + 1].v; 113 } 114 void Update(int root, int l, int r, int add) 115 { 116 if (tree[root].r<l || tree[root].l>r) return; 117 if (l <= tree[root].l&&tree[root].r <= r) 118 { 119 tree[root].tmp += add; 120 tree[root].v += add * (tree[root].r - tree[root].l + 1); 121 return; 122 } 123 Pushdown(root); 124 int mid = (tree[root].r + tree[root].l) / 2; 125 if (l <= mid)Update(root * 2, l, r, add); 126 if (r>mid)Update(root * 2 + 1, l, r, add); 127 PushUp(root); 128 } 129 130 long long Query(int root, int l, int r) 131 { 132 if (tree[root].r<l || tree[root].l>r) return 0; 133 if (l <= tree[root].l&&tree[root].r <= r) 134 { 135 return tree[root].v; 136 } 137 Pushdown(root); 138 long long tsum = Query(root * 2, l, r) + Query(root * 2 + 1, l, r); 139 PushUp(root); 140 return tsum; 141 } 142 /*-------线段树·终————*/ 143 144 long long Query_length(int x, int y) 145 {//查询结点x到y路径上所有结点值之和 146 long long ans = 0; 147 int fx = top[x], fy = top[y]; 148 while (fx != fy) 149 { 150 if (dep[fx] >= dep[fy]) 151 { 152 ans += Query(1, nid[fx], nid[x]);//在一条重链上的值用线段树维护、查询 153 x = father[fx]; 154 fx = top[x]; 155 } 156 else 157 { 158 ans += Query(1, nid[fy], nid[y]); 159 y = father[fy]; 160 fy = top[y]; 161 } 162 } 163 //此时x与y已经在一条重链上,而重链上的编号都是连续的 164 if (x != y) 165 { 166 if (nid[x] < nid[y]) 167 { 168 ans += Query(1, nid[x], nid[y]); 169 } 170 else 171 { 172 ans += Query(1, nid[y], nid[x]); 173 } 174 } 175 else ans += Query(1, nid[x], nid[y]); 176 return ans; 177 } 178 179 void Update_path(int x, int y, int add) 180 {//将x到y路径上所有结点的值都加上add 181 int fx = top[x], fy = top[y]; 182 while (fx != fy) 183 { 184 if (dep[fx] >= dep[fy]) 185 { 186 Update(1, nid[fx], nid[x], add); 187 x = father[fx]; 188 fx = top[x]; 189 } 190 else 191 { 192 Update(1, nid[fy], nid[y], add); 193 y = father[fy]; 194 fy = top[y]; 195 } 196 } 197 if (x != y) 198 { 199 if (nid[x] < nid[y]) Update(1, nid[x], nid[y], add); 200 else Update(1, nid[y], nid[x], add); 201 } 202 else Update(1, nid[x], nid[y], add); 203 } 204 /*-------树链剖分·终-------*/ 205 206 int main() 207 { 208 int n, m, p; 209 while (~scanf("%d%d%d", &n, &m, &p)) 210 { 211 INIT(); 212 for (int i = 1; i <= n; i++) scanf("%d", &val[i]); 213 for (int i = 1; i <= m; i++) 214 { 215 int from, to; 216 scanf("%d%d", &from, &to); 217 addEdge(from, to); 218 } 219 dfs1(1, 1, 1); 220 dfs2(1, 1); 221 BuildTree(1, 1, n); 222 char s[10]; 223 for (int i = 1; i <= p; i++) 224 { 225 scanf("%s", s); 226 int c1, c2, k, c; 227 switch (s[0]) 228 { 229 case 'I': 230 scanf("%d%d%d", &c1, &c2, &k); 231 Update_path(c1, c2, k); 232 break; 233 case 'D': 234 scanf("%d%d%d", &c1, &c2, &k); 235 Update_path(c1, c2, -k); 236 break; 237 case 'Q': 238 scanf("%d", &c); 239 printf("%lld\n", Query(1, nid[c], nid[c])); 240 break; 241 } 242 } 243 } 244 return 0; 245 }
2、HYSBZ - 2243 染色
题意:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 using namespace std; 5 const int maxn = 100000+ 10; 6 7 /*-------树链剖分·启-------*/ 8 9 int siz[maxn];//size[i]:以i为根的子树结点个数 10 int top[maxn];//保存结点i所在链的顶端结点 11 int son[maxn];//保存i的重儿子 12 int dep[maxn];//保存结点i的层次(深度) 13 int father[maxn];//保存结点i的父亲结点 14 int nid[maxn];//保存树节点剖分后的对应新编号 15 int oid[maxn];//保存新编号对应在剖分的树中的结点(与nid相反) 16 int cnt = 0;//重编号 17 int val[maxn];//结点值 18 struct EDGE 19 { 20 int from, to, next; 21 EDGE(int ff = 0, int tt = 0, int nn = 0) :from(ff), to(tt), next(nn) {} 22 }edge[maxn * 2]; 23 int Head[maxn], totedge = 0; 24 void addEdge(int from, int to) 25 { 26 edge[totedge] = EDGE(from, to, Head[from]); 27 Head[from] = totedge++; 28 edge[totedge] = EDGE(to, from, Head[to]); 29 Head[to] = totedge++; 30 } 31 void INIT() 32 { 33 memset(Head, -1, sizeof(Head)); 34 totedge = 0; 35 36 memset(son, -1, sizeof(son)); 37 cnt = 0; 38 } 39 40 void dfs1(int u, int fa, int layer) 41 { 42 dep[u] = layer; 43 father[u] = fa; 44 siz[u] = 1; 45 for (int i = Head[u]; i != -1; i = edge[i].next) 46 { 47 int v = edge[i].to; 48 if (v != fa) 49 { 50 dfs1(v, u, layer + 1); 51 siz[u] += siz[v]; 52 if (son[u] == -1 || siz[v] > siz[son[u]]) 53 { 54 son[u] = v; 55 } 56 } 57 } 58 } 59 60 void dfs2(int u, int Hson) 61 {//Hson,重儿子 62 top[u] = Hson; 63 nid[u] = ++cnt; 64 oid[cnt] = u; 65 if (son[u] == -1) return; 66 dfs2(son[u], Hson);//先将当前重链重编号 67 for (int i = Head[u]; i != -1; i = edge[i].next) 68 {//对不在重链上的点,自己作为子树的重链起点重编号 69 int v = edge[i].to; 70 if (v != son[u] && v != father[u]) dfs2(v, v); 71 } 72 } 73 /*-------线段树·启————*/ 74 struct treenode 75 { 76 int l, r; 77 int v, l_color, r_color; 78 int delay; 79 treenode(int ll = 0, int rr = 0,int vv = 0, int lc = 0,int rc=0,int dd=0) :l(ll), r(rr), v(vv),l_color(lc),r_color(rc),delay(dd){} 80 }tree[maxn * 4]; 81 82 void PushUp(int root) 83 { 84 int lson = root * 2, rson = root * 2 + 1; 85 tree[root].v = tree[lson].v + tree[rson].v; 86 if (tree[lson].r_color == tree[rson].l_color) tree[root].v--; 87 tree[root].l_color = tree[lson].l_color, tree[root].r_color = tree[rson].r_color; 88 } 89 90 void BuildTree(int root, int l, int r) 91 { 92 tree[root].l = l, tree[root].r = r; 93 tree[root].delay = 0; 94 if (l == r) 95 { 96 tree[root].v = 1; 97 tree[root].l_color=tree[root].r_color = val[oid[l]]; 98 return; 99 } 100 int mid = (l + r) / 2; 101 BuildTree(root * 2, l, mid); 102 BuildTree(root * 2 + 1, mid + 1, r); 103 PushUp(root); 104 } 105 106 void PushDown(int root) 107 { 108 int lson = root * 2, rson = root * 2 + 1; 109 if (tree[root].delay) 110 { 111 tree[lson].v = tree[rson].v = 1; 112 tree[lson].l_color = tree[lson].r_color = tree[root].delay; 113 tree[rson].l_color = tree[rson].r_color = tree[root].delay; 114 tree[lson].delay = tree[rson].delay = tree[root].delay; 115 tree[root].delay = 0; 116 } 117 } 118 119 void Update(int root, int l, int r, int nc) 120 { 121 if (tree[root].r<l || tree[root].l>r) return; 122 if (l <= tree[root].l&&tree[root].r <= r) 123 { 124 tree[root].delay = nc; 125 tree[root].l_color = tree[root].r_color = nc; 126 tree[root].v =1; 127 return; 128 } 129 PushDown(root); 130 int mid = (tree[root].r + tree[root].l) / 2; 131 if (l <= mid)Update(root * 2, l, r, nc); 132 if (r>mid)Update(root * 2 + 1, l, r, nc); 133 PushUp(root); 134 } 135 136 int Query(int root, int l, int r,int&rcolor) 137 { 138 if (tree[root].r<l || tree[root].l>r) return 0; 139 if (l <= tree[root].l&&tree[root].r <= r) 140 { 141 if (rcolor == tree[root].l_color) 142 { 143 rcolor = tree[root].r_color; 144 return tree[root].v - 1; 145 } 146 else 147 { 148 rcolor = tree[root].r_color; 149 return tree[root].v; 150 } 151 } 152 PushDown(root); 153 int mid = (tree[root].l + tree[root].r) / 2; 154 int ans = 0; 155 if (l <= mid) ans += Query(root * 2, l, r, rcolor); 156 if (r > mid) ans += Query(root * 2 + 1, l, r, rcolor); 157 PushUp(root); 158 return ans; 159 } 160 161 int Query_color(int root, int pos ,char flag) 162 {//查询某个分段最左或最右的颜色 163 if (tree[root].l == pos&&flag=='l') 164 { 165 return tree[root].l_color; 166 } 167 else if (tree[root].r == pos && flag == 'r') 168 { 169 return tree[root].r_color; 170 } 171 PushDown(root); 172 int mid = (tree[root].l + tree[root].r) / 2; 173 int ans = 0; 174 if (pos <= mid) ans = Query_color(root * 2, pos,flag); 175 else ans = Query_color(root * 2 + 1, pos,flag); 176 PushUp(root); 177 return ans; 178 } 179 180 181 /*-------线段树·终————*/ 182 183 int Query_length(int x, int y) 184 {//查询结点x到y路径上颜色段数 185 int ans = 0; 186 int fx = top[x], fy = top[y]; 187 while (fx != fy) 188 { 189 if (dep[fx] >= dep[fy]) 190 { 191 int rcolor = -1; 192 ans += Query(1, nid[fx], nid[x],rcolor);//在一条重链上的值用线段树维护、查询 193 int tlcolor = Query_color(1, nid[fx], 'l'); 194 x = father[fx]; 195 fx = top[x]; 196 int trcolor = Query_color(1, nid[x], 'r'); 197 if (trcolor ==tlcolor) ans--; 198 } 199 else 200 { 201 int rcolor = -1; 202 ans += Query(1, nid[fy], nid[y],rcolor); 203 int tlcolor = Query_color(1, nid[fy], 'l'); 204 y = father[fy]; 205 fy = top[y]; 206 int trcolor = Query_color(1, nid[y], 'r'); 207 if (trcolor == tlcolor) ans--; 208 } 209 } 210 //此时x与y已经在一条重链上,而重链上的编号都是连续的 211 int rcolor = -1; 212 if (x != y) 213 { 214 215 if (nid[x] < nid[y]) 216 { 217 ans += Query(1, nid[x], nid[y],rcolor); 218 } 219 else 220 { 221 ans += Query(1, nid[y], nid[x],rcolor); 222 } 223 } 224 else ans += Query(1, nid[x], nid[y], rcolor); 225 return ans; 226 } 227 228 void Update_path(int x, int y, int nc) 229 {//将x到y路径上所有结点的值都加上add 230 int fx = top[x], fy = top[y]; 231 while (fx != fy) 232 { 233 if (dep[fx] >= dep[fy]) 234 { 235 Update(1, nid[fx], nid[x], nc); 236 x = father[fx]; 237 fx = top[x]; 238 } 239 else 240 { 241 Update(1, nid[fy], nid[y], nc); 242 y = father[fy]; 243 fy = top[y]; 244 } 245 } 246 if (x != y) 247 { 248 if (nid[x] < nid[y]) Update(1, nid[x], nid[y], nc); 249 else Update(1, nid[y], nid[x], nc); 250 } 251 else Update(1, nid[x], nid[y], nc); 252 } 253 /*-------树链剖分·终-------*/ 254 255 int main() 256 { 257 int n, m; 258 while (~scanf("%d%d", &n, &m)) 259 { 260 INIT(); 261 for (int i = 1; i <= n; i++) scanf("%d", &val[i]); 262 for (int i = 1; i < n; i++) 263 { 264 int u, v; 265 scanf("%d%d", &u, &v); 266 addEdge(u, v); 267 } 268 dfs1(1,1,1); 269 dfs2(1, 1); 270 BuildTree(1, 1, n); 271 char s[10]; 272 for (int i = 1; i <= m; i++) 273 { 274 scanf("%s", s); 275 if (s[0] == 'Q') 276 { 277 int u, v; 278 scanf("%d%d", &u, &v); 279 printf("%d\n", Query_length(u, v)); 280 } 281 else 282 { 283 int u, v, c; 284 scanf("%d%d%d", &u, &v, &c); 285 Update_path(u, v, c); 286 } 287 } 288 } 289 return 0; 290 }
3、HYSBZ - 1036 树的统计Count
题意:一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成一些操作:
I. CHANGE u t : 把结点u的权值改为t
II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值
III. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身
思路:树链剖分+线段树,点权,单点更新+区间查询。线段树维护区间和和最大值。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<algorithm> 5 using namespace std; 6 const int maxn = 30000 + 10; 7 const int INF = 0x3f3f3f3f; 8 9 /*-------树链剖分·启-------*/ 10 11 int siz[maxn];//size[i]:以i为根的子树结点个数 12 int top[maxn];//保存结点i所在链的顶端结点 13 int son[maxn];//保存i的重儿子 14 int dep[maxn];//保存结点i的层次(深度) 15 int father[maxn];//保存结点i的父亲结点 16 int nid[maxn];//保存树节点剖分后的对应新编号 17 int oid[maxn];//保存新编号对应在剖分的树中的结点(与nid相反) 18 int cnt = 0;//重编号 19 int val[maxn];//结点值 20 struct EDGE 21 { 22 int from, to, next; 23 EDGE(int ff = 0, int tt = 0, int nn = 0) :from(ff), to(tt), next(nn) {} 24 }edge[maxn * 2]; 25 int Head[maxn], totedge = 0; 26 void addEdge(int from, int to) 27 { 28 edge[totedge] = EDGE(from, to, Head[from]); 29 Head[from] = totedge++; 30 edge[totedge] = EDGE(to, from, Head[to]); 31 Head[to] = totedge++; 32 } 33 void INIT() 34 { 35 memset(Head, -1, sizeof(Head)); 36 totedge = 0; 37 38 memset(son, -1, sizeof(son)); 39 cnt = 0; 40 } 41 42 void dfs1(int u, int fa, int layer) 43 { 44 dep[u] = layer; 45 father[u] = fa; 46 siz[u] = 1; 47 for (int i = Head[u]; i != -1; i = edge[i].next) 48 { 49 int v = edge[i].to; 50 if (v != fa) 51 { 52 dfs1(v, u, layer + 1); 53 siz[u] += siz[v]; 54 if (son[u] == -1 || siz[v] > siz[son[u]]) 55 { 56 son[u] = v; 57 } 58 } 59 } 60 } 61 62 void dfs2(int u, int Hson) 63 {//Hson,重儿子 64 top[u] = Hson; 65 nid[u] = ++cnt; 66 oid[cnt] = u; 67 if (son[u] == -1) return; 68 dfs2(son[u], Hson);//先将当前重链重编号 69 for (int i = Head[u]; i != -1; i = edge[i].next) 70 {//对不在重链上的点,自己作为子树的重链起点重编号 71 int v = edge[i].to; 72 if (v != son[u] && v != father[u]) dfs2(v, v); 73 } 74 } 75 /*-------线段树·启————*/ 76 struct treenode 77 { 78 int l, r; 79 long long sum; 80 int max, delay; 81 treenode(int ll = 0, int rr = 0, long long vv = 0, int mx=0,long long tt = 0) :l(ll), r(rr), sum(vv),max(mx), delay(tt) {} 82 }tree[maxn * 4]; 83 84 void PushUp(int root) 85 { 86 tree[root].sum = tree[root * 2].sum + tree[root * 2 + 1].sum; 87 tree[root].max = max(tree[root * 2].max, tree[root * 2 + 1].max); 88 } 89 90 void BuildTree(int root, int l, int r) 91 { 92 tree[root].l = l, tree[root].r = r; 93 tree[root].delay = 0; 94 if (l == r) 95 { 96 tree[root].sum = tree[root].max=val[oid[l]]; 97 return; 98 } 99 int mid = (l + r) / 2; 100 BuildTree(root * 2, l, mid); 101 BuildTree(root * 2 + 1, mid + 1, r); 102 PushUp(root); 103 } 104 void Pushdown(int root) 105 { 106 int lson = root * 2, rson = root * 2 + 1; 107 if (tree[root].delay) 108 { 109 tree[lson].sum =1ll* (tree[lson].r - tree[lson].l + 1)*tree[root].delay; 110 tree[rson].sum = 1ll*(tree[rson].r - tree[rson].l + 1)*tree[root].delay; 111 tree[lson].delay = tree[root].delay; 112 tree[rson].delay = tree[root].delay; 113 tree[lson].max = tree[rson].max = tree[root].delay; 114 tree[root].delay = 0; 115 } 116 } 117 118 void Update(int root, int l, int r, int v) 119 { 120 if (tree[root].r<l || tree[root].l>r) return; 121 if (l <= tree[root].l&&tree[root].r <= r) 122 { 123 tree[root].delay = v; 124 tree[root].max = v; 125 tree[root].sum = 1ll*v * (tree[root].r - tree[root].l + 1); 126 return; 127 } 128 Pushdown(root); 129 int mid = (tree[root].r + tree[root].l) / 2; 130 if (l <= mid)Update(root * 2, l, r, v); 131 if (r>mid)Update(root * 2 + 1, l, r, v); 132 PushUp(root); 133 } 134 135 pair<long long,int> Query(int root, int l, int r) 136 { 137 if (tree[root].r<l || tree[root].l>r) return make_pair(0,0); 138 if (l <= tree[root].l&&tree[root].r <= r) 139 { 140 return make_pair(tree[root].sum,tree[root].max); 141 } 142 Pushdown(root); 143 int mid = (tree[root].l + tree[root].r) / 2; 144 bool flag1 = false, flag2 = false; 145 pair<long long, int>ans,tmp1= pair<long long, int>(0,0),tmp2= pair<long long, int>(0,0); 146 if (l <= mid) tmp1 = Query(root * 2, l, r),flag1=true; 147 if (r > mid) tmp2 = Query(root * 2 + 1, l, r),flag2=true; 148 PushUp(root); 149 if (flag1&&flag2) ans.first = tmp1.first + tmp2.first, ans.second = max(tmp1.second, tmp2.second); 150 else if (flag1) ans = tmp1; 151 else ans = tmp2; 152 return ans; 153 } 154 /*-------线段树·终————*/ 155 156 pair<long long, int> Query_length(int x, int y) 157 {//查询结点x到y路径上所有结点值之和与最大值 158 long long sum = 0; 159 int maxv = -INF; 160 int fx = top[x], fy = top[y]; 161 pair<long long, int>tmp; 162 while (fx != fy) 163 { 164 if (dep[fx] >= dep[fy]) 165 { 166 tmp= Query(1, nid[fx], nid[x]);//在一条重链上的值用线段树维护、查询 167 x = father[fx]; 168 fx = top[x]; 169 sum += tmp.first, maxv = max(maxv, tmp.second); 170 } 171 else 172 { 173 tmp= Query(1, nid[fy], nid[y]); 174 sum += tmp.first, maxv = max(maxv, tmp.second); 175 y = father[fy]; 176 fy = top[y]; 177 } 178 } 179 //此时x与y已经在一条重链上,而重链上的编号都是连续的 180 if (x != y) 181 { 182 if (nid[x] < nid[y]) 183 { 184 tmp= Query(1, nid[x], nid[y]); 185 sum += tmp.first, maxv = max(maxv, tmp.second); 186 } 187 else 188 { 189 tmp= Query(1, nid[y], nid[x]); 190 sum += tmp.first, maxv = max(maxv, tmp.second); 191 } 192 } 193 else 194 { 195 tmp = Query(1, nid[x], nid[y]); 196 sum += tmp.first, maxv = max(maxv, tmp.second); 197 } 198 return make_pair(sum,maxv); 199 } 200 201 void Update_path(int x, int y, int add) 202 {//将x到y路径上所有结点的值都加上add 203 int fx = top[x], fy = top[y]; 204 while (fx != fy) 205 { 206 if (dep[fx] >= dep[fy]) 207 { 208 Update(1, nid[fx], nid[x], add); 209 x = father[fx]; 210 fx = top[x]; 211 } 212 else 213 { 214 Update(1, nid[fy], nid[y], add); 215 y = father[fy]; 216 fy = top[y]; 217 } 218 } 219 if (x != y) 220 { 221 if (nid[x] < nid[y]) Update(1, nid[x], nid[y], add); 222 else Update(1, nid[y], nid[x], add); 223 } 224 else Update(1, nid[x], nid[y], add); 225 } 226 /*-------树链剖分·终-------*/ 227 228 int main() 229 { 230 int n,q; 231 while (~scanf("%d", &n)) 232 { 233 INIT(); 234 235 for (int i = 1; i <n; i++) 236 { 237 int from, to; 238 scanf("%d%d", &from, &to); 239 addEdge(from, to); 240 } 241 for (int i = 1; i <= n; i++) scanf("%d", &val[i]); 242 dfs1(1, 1, 1); 243 dfs2(1, 1); 244 BuildTree(1, 1, n); 245 char s[10]; 246 scanf("%d", &q); 247 for (int i = 1; i <= q; i++) 248 { 249 scanf("%s", s); 250 if (s[1] == 'H') 251 { 252 int u, t; 253 scanf("%d%d", &u, &t); 254 Update(1, nid[u], nid[u], t); 255 } 256 else 257 { 258 int u, v; 259 scanf("%d%d", &u, &v); 260 pair<long long, int>ans = Query_length(u, v); 261 if (s[1] == 'M') printf("%d\n", ans.second); 262 else printf("%lld\n", ans.first); 263 } 264 } 265 } 266 return 0; 267 }
4、FZU - 2082 过路费
题意:有n座城市,由n-1条路相连通,使得任意两座城市之间可达。每条路有过路费,要交过路费才能通过。每条路的过路费经常会更新,现问你,当前情况下,从城市a到城市b最少要花多少过路费。
思路:树链剖分+线段树,边权,单点更新+区间查询。注意对边进行编号,以及一些辅助数组记录边指向的结点、边权。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<iostream> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int maxn = 50000 + 10; 6 7 /*-------树链剖分·启-------*/ 8 9 int siz[maxn];//size[i]:以i为根的子树结点个数 10 int top[maxn];//保存结点i所在链的顶端结点 11 int son[maxn];//保存i的重儿子 12 int dep[maxn];//保存结点i的层次(深度) 13 int father[maxn];//保存结点i的父亲结点 14 int nid[maxn];//保存树剖分后的指向子结点的边对应的新编号 15 int nval[maxn];//记录所指向的子结点i新编号对应边的边权,用以建立线段树 16 int oid[maxn];//保存新编号对应在剖分的树中的所指向的子结点(与nid相反) 17 int cnt = 0;//重编号 18 int val[maxn];//原树中指向子结点i的边的边权值 19 int linkto[maxn];//记录指向的子结点 20 struct EDGE 21 { 22 int from, to, w, next; 23 EDGE(int ff = 0, int tt = 0, int ww = 0, int nn = 0) :from(ff), to(tt), w(ww), next(nn) {} 24 }edge[maxn * 2]; 25 int Head[maxn], totedge = 0; 26 void addEdge(int from, int to, int w) 27 { 28 edge[totedge] = EDGE(from, to, w, Head[from]); 29 Head[from] = totedge++; 30 edge[totedge] = EDGE(to, from, w, Head[to]); 31 Head[to] = totedge++; 32 } 33 int treeroot = 1; 34 void INIT() 35 { 36 memset(Head, -1, sizeof(Head)); 37 totedge = 0; 38 39 memset(son, -1, sizeof(son)); 40 memset(siz, 0, sizeof(siz)); 41 memset(father, 0, sizeof(father)); 42 memset(top, 0, sizeof(top)); 43 memset(dep, 0, sizeof(dep)); 44 cnt = 0; 45 } 46 47 void dfs1(int u, int fa, int layer) 48 { 49 dep[u] = layer; 50 father[u] = fa; 51 siz[u] = 1; 52 for (int i = Head[u]; i != -1; i = edge[i].next) 53 { 54 int v = edge[i].to; 55 if (v != fa) 56 { 57 dfs1(v, u, layer + 1); 58 siz[u] += siz[v]; 59 linkto[i / 2 + 1] = v; 60 val[v] = edge[i].w; 61 if (son[u] == -1 || siz[v] > siz[son[u]]) 62 { 63 son[u] = v; 64 } 65 } 66 } 67 } 68 69 void dfs2(int u, int Hson) 70 {//Hson,重儿子 71 top[u] = Hson; 72 if (u != treeroot) 73 { 74 nid[u] = ++cnt; 75 oid[cnt] = u; 76 nval[cnt] = val[u]; 77 } 78 if (son[u] == -1) return; 79 dfs2(son[u], Hson);//先将当前重链重编号 80 for (int i = Head[u]; i != -1; i = edge[i].next) 81 {//对不在重链上的点,自己作为子树的重链起点重编号 82 int v = edge[i].to; 83 if (v != son[u] && v != father[u]) dfs2(v, v); 84 } 85 } 86 /*-------线段树·启————*/ 87 struct treenode 88 { 89 int l, r; 90 long long v, tmp; 91 treenode(int ll = 0, int rr = 0, long long vv = 0, long long tt = 0) :l(ll), r(rr), v(vv), tmp(tt) {} 92 }tree[maxn * 4]; 93 94 void BuildTree(int root, int l, int r) 95 { 96 tree[root].l = l, tree[root].r = r; 97 tree[root].tmp = 0; 98 if (l == r) 99 { 100 tree[root].v = nval[l]; 101 return; 102 } 103 int mid = (l + r) / 2; 104 BuildTree(root * 2, l, mid); 105 BuildTree(root * 2 + 1, mid + 1, r); 106 tree[root].v = tree[root * 2].v + tree[root * 2 + 1].v; 107 } 108 void Pushdown(int root) 109 { 110 int lson = root * 2, rson = root * 2 + 1; 111 if (tree[root].tmp) 112 { 113 tree[lson].v = (tree[lson].r - tree[lson].l + 1)*tree[root].tmp; 114 tree[rson].v = (tree[rson].r - tree[rson].l + 1)*tree[root].tmp; 115 tree[lson].tmp = tree[root].tmp; 116 tree[rson].tmp = tree[root].tmp; 117 tree[root].tmp = 0; 118 } 119 } 120 void PushUp(int root) 121 { 122 tree[root].v = tree[root * 2].v + tree[root * 2 + 1].v; 123 } 124 void Update(int root, int l, int r, int add) 125 { 126 if (tree[root].r<l || tree[root].l>r) return; 127 if (l <= tree[root].l&&tree[root].r <= r) 128 { 129 tree[root].tmp = add; 130 tree[root].v = add * (tree[root].r - tree[root].l + 1); 131 return; 132 } 133 Pushdown(root); 134 int mid = (tree[root].r + tree[root].l) / 2; 135 if (l <= mid)Update(root * 2, l, r, add); 136 if (r>mid)Update(root * 2 + 1, l, r, add); 137 PushUp(root); 138 } 139 140 long long Query(int root, int l, int r) 141 { 142 if (tree[root].r<l || tree[root].l>r) return 0; 143 if (l <= tree[root].l&&tree[root].r <= r) 144 { 145 return tree[root].v; 146 } 147 Pushdown(root); 148 long long tsum = Query(root * 2, l, r) + Query(root * 2 + 1, l, r); 149 PushUp(root); 150 return tsum; 151 } 152 /*-------线段树·终————*/ 153 154 long long Query_length(int x, int y) 155 {//查询x到y路径上边权和 156 int fx = top[x], fy = top[y]; 157 long long ans = 0; 158 while (fx != fy) 159 { 160 if (dep[fx] > dep[fy]) 161 { 162 int id1 = nid[fx], id2 = nid[x]; 163 ans += Query(1, id1, id2); 164 x = father[fx]; 165 fx = top[x]; 166 } 167 else 168 { 169 int id1 = nid[fy], id2 = nid[y]; 170 ans += Query(1, id1, id2); 171 y = father[fy]; 172 fy = top[y]; 173 } 174 } 175 if (x != y) 176 { 177 if (dep[x] > dep[y]) 178 { 179 int id1 = nid[son[y]], id2 = nid[x]; 180 ans += Query(1, id1, id2); 181 } 182 else 183 { 184 int id1 = nid[son[x]], id2 = nid[y]; 185 ans += Query(1, id1, id2); 186 } 187 } 188 return ans; 189 } 190 void Update_path(int x, int y, int add) 191 {//将x到y路径上所有边的值都加上或修改为add 192 int fx = top[x], fy = top[y]; 193 while (fx != fy) 194 { 195 if (dep[fx] >= dep[fy]) 196 { 197 Update(1, nid[fx], nid[x], add); 198 x = father[fx]; 199 fx = top[x]; 200 } 201 else 202 { 203 Update(1, nid[fy], nid[y], add); 204 y = father[fy]; 205 fy = top[y]; 206 } 207 } 208 if (x != y) 209 { 210 if (dep[x] < dep[y]) Update(1, nid[son[x]], nid[y], add); 211 else Update(1, nid[son[y]], nid[x], add); 212 } 213 } 214 /*-------树链剖分·终-------*/ 215 216 int main() 217 { 218 int n, m; 219 while (~scanf("%d%d", &n, &m)) 220 { 221 INIT(); 222 for (int i = 1; i < n; i++) 223 { 224 int u, v, w; 225 scanf("%d%d%d", &u, &v, &w); 226 addEdge(u, v, w); 227 } 228 dfs1(1, 1, 1); 229 dfs2(1, 1); 230 BuildTree(1, 1, cnt); 231 for (int i = 1; i <= m; i++) 232 { 233 int flag; 234 scanf("%d", &flag); 235 if (flag == 1) 236 { 237 int u,v; 238 scanf("%d%d", &u,&v); 239 long long ans = Query_length(u,v); 240 printf("%lld\n", ans); 241 } 242 else 243 { 244 int id, v; 245 scanf("%d%d", &id, &v); 246 int nID = nid[linkto[id]]; 247 Update(1, nID, nID, v); 248 } 249 250 } 251 252 } 253 return 0; 254 }
5、LightOJ - 1348 Aladdin and the Return Journey
题意:有一棵树,每次更新一个点的权值或者查询u到v路径上所有结点权值之和。
思路:树链剖分+线段树,点权,单点更新和区间查询。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 using namespace std; 5 const int maxn = 30000 + 10; 6 7 /*-------树链剖分·启-------*/ 8 9 int siz[maxn];//size[i]:以i为根的子树结点个数 10 int top[maxn];//保存结点i所在链的顶端结点 11 int son[maxn];//保存i的重儿子 12 int dep[maxn];//保存结点i的层次(深度) 13 int father[maxn];//保存结点i的父亲结点 14 int nid[maxn];//保存树节点剖分后的对应新编号 15 int oid[maxn];//保存新编号对应在剖分的树中的结点(与nid相反) 16 int cnt = 0;//重编号 17 int val[maxn];//结点值 18 struct EDGE 19 { 20 int from, to, next; 21 EDGE(int ff = 0, int tt = 0, int nn = 0) :from(ff), to(tt), next(nn) {} 22 }edge[maxn * 2]; 23 int Head[maxn], totedge = 0; 24 void addEdge(int from, int to) 25 { 26 edge[totedge] = EDGE(from, to, Head[from]); 27 Head[from] = totedge++; 28 edge[totedge] = EDGE(to, from, Head[to]); 29 Head[to] = totedge++; 30 } 31 void INIT() 32 { 33 memset(Head, -1, sizeof(Head)); 34 totedge = 0; 35 36 memset(son, -1, sizeof(son)); 37 memset(siz, 0, sizeof(siz)); 38 memset(father, 0, sizeof(father)); 39 memset(top, 0, sizeof(top)); 40 memset(dep, 0, sizeof(dep)); 41 cnt = 0; 42 } 43 44 void dfs1(int u, int fa, int layer) 45 { 46 dep[u] = layer; 47 father[u] = fa; 48 siz[u] = 1; 49 for (int i = Head[u]; i != -1; i = edge[i].next) 50 { 51 int v = edge[i].to; 52 if (v != fa) 53 { 54 dfs1(v, u, layer + 1); 55 siz[u] += siz[v]; 56 if (son[u] == -1 || siz[v] > siz[son[u]]) 57 { 58 son[u] = v; 59 } 60 } 61 } 62 } 63 64 void dfs2(int u, int Hson) 65 {//Hson,重儿子 66 top[u] = Hson; 67 nid[u] = ++cnt; 68 oid[cnt] = u; 69 if (son[u] == -1) return; 70 dfs2(son[u], Hson);//先将当前重链重编号 71 for (int i = Head[u]; i != -1; i = edge[i].next) 72 {//对不在重链上的点,自己作为子树的重链起点重编号 73 int v = edge[i].to; 74 if (v != son[u] && v != father[u]) dfs2(v, v); 75 } 76 } 77 /*-------线段树·启————*/ 78 struct treenode 79 { 80 int l, r; 81 long long v, delay; 82 treenode(int ll = 0, int rr = 0, long long vv = 0, long long tt = 0) :l(ll), r(rr), v(vv), delay(tt) {} 83 }tree[maxn * 4]; 84 85 void PushUp(int root) 86 { 87 tree[root].v = tree[root * 2].v + tree[root * 2 + 1].v; 88 } 89 void BuildTree(int root, int l, int r) 90 { 91 tree[root].l = l, tree[root].r = r; 92 tree[root].delay = 0; 93 if (l == r) 94 { 95 tree[root].v = val[oid[l]]; 96 return; 97 } 98 int mid = (l + r) / 2; 99 BuildTree(root * 2, l, mid); 100 BuildTree(root * 2 + 1, mid + 1, r); 101 tree[root].v = tree[root * 2].v + tree[root * 2 + 1].v; 102 } 103 void Pushdown(int root) 104 { 105 int lson = root * 2, rson = root * 2 + 1; 106 if (tree[root].delay) 107 { 108 tree[lson].v = (tree[lson].r - tree[lson].l + 1)*tree[root].delay; 109 tree[rson].v = (tree[rson].r - tree[rson].l + 1)*tree[root].delay; 110 tree[lson].delay = tree[root].delay; 111 tree[rson].delay = tree[root].delay; 112 tree[root].delay = 0; 113 } 114 } 115 116 void Update(int root, int l, int r, int add) 117 { 118 if (tree[root].r<l || tree[root].l>r) return; 119 if (l <= tree[root].l&&tree[root].r <= r) 120 { 121 tree[root].delay = add; 122 tree[root].v = add * (tree[root].r - tree[root].l + 1); 123 return; 124 } 125 Pushdown(root); 126 int mid = (tree[root].r + tree[root].l) / 2; 127 if (l <= mid)Update(root * 2, l, r, add); 128 if (r>mid)Update(root * 2 + 1, l, r, add); 129 PushUp(root); 130 } 131 132 long long Query(int root, int l, int r) 133 { 134 if (tree[root].r<l || tree[root].l>r) return 0; 135 if (l <= tree[root].l&&tree[root].r <= r) 136 { 137 return tree[root].v; 138 } 139 Pushdown(root); 140 long long tsum = Query(root * 2, l, r) + Query(root * 2 + 1, l, r); 141 PushUp(root); 142 return tsum; 143 } 144 /*-------线段树·终————*/ 145 146 long long Query_length(int x, int y) 147 {//查询结点x到y路径上所有结点值之和 148 long long ans = 0; 149 int fx = top[x], fy = top[y]; 150 while (fx != fy) 151 { 152 if (dep[fx] >= dep[fy]) 153 { 154 ans += Query(1, nid[fx], nid[x]);//在一条重链上的值用线段树维护、查询 155 x = father[fx]; 156 fx = top[x]; 157 } 158 else 159 { 160 ans += Query(1, nid[fy], nid[y]); 161 y = father[fy]; 162 fy = top[y]; 163 } 164 } 165 //此时x与y已经在一条重链上,而重链上的编号都是连续的 166 if (x != y) 167 { 168 if (nid[x] < nid[y]) 169 { 170 ans += Query(1, nid[x], nid[y]); 171 } 172 else 173 { 174 ans += Query(1, nid[y], nid[x]); 175 } 176 } 177 else ans += Query(1, nid[x], nid[y]); 178 return ans; 179 } 180 181 void Update_path(int x, int y, int add) 182 {//将x到y路径上所有结点的值都加上add 183 int fx = top[x], fy = top[y]; 184 while (fx != fy) 185 { 186 if (dep[fx] >= dep[fy]) 187 { 188 Update(1, nid[fx], nid[x], add); 189 x = father[fx]; 190 fx = top[x]; 191 } 192 else 193 { 194 Update(1, nid[fy], nid[y], add); 195 y = father[fy]; 196 fy = top[y]; 197 } 198 } 199 if (x != y) 200 { 201 if (nid[x] < nid[y]) Update(1, nid[x], nid[y], add); 202 else Update(1, nid[y], nid[x], add); 203 } 204 else Update(1, nid[x], nid[y], add); 205 } 206 /*-------树链剖分·终-------*/ 207 208 int main() 209 { 210 int t,n,q; 211 int Case = 1; 212 scanf("%d", &t); 213 while (t--) 214 { 215 printf("Case %d:\n", Case++); 216 scanf("%d", &n); 217 INIT(); 218 for (int i = 1; i <= n; i++) scanf("%d", &val[i]); 219 for (int i = 1; i <n; i++) 220 { 221 int from, to; 222 scanf("%d%d", &from, &to); 223 from++, to++;//改为从1开始编号 224 addEdge(from, to); 225 } 226 dfs1(1, 1, 1); 227 dfs2(1, 1); 228 BuildTree(1, 1, n); 229 scanf("%d", &q); 230 for (int i = 1; i <= q; i++) 231 { 232 int op; 233 scanf("%d", &op); 234 if (op == 0) 235 { 236 int u, v; 237 scanf("%d%d", &u, &v); 238 u++, v++; 239 printf("%lld\n", Query_length(u, v)); 240 } 241 else 242 { 243 int u, t; 244 scanf("%d%d", &u, &t); 245 u++; 246 Update(1, nid[u], nid[u], t); 247 } 248 } 249 } 250 return 0; 251 }
6、Housewife Wind POJ - 2763
题意:有一个小镇,有n户人家和n-1条路(树),有一位母亲要去接孩子,起点位于s。两种操作:修改通过某一条路的时间;母亲要从当前位置到达u的位置接孩子,求时间。
思路:树链剖分+线段树,边权,区间查询+单点更新。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<iostream> 2 #include<cstring> 3 using namespace std; 4 const int maxn = 100000+10; 5 6 /*-------树链剖分·启-------*/ 7 8 int siz[maxn];//size[i]:以i为根的子树结点个数 9 int top[maxn];//保存结点i所在链的顶端结点 10 int son[maxn];//保存i的重儿子 11 int dep[maxn];//保存结点i的层次(深度) 12 int father[maxn];//保存结点i的父亲结点 13 int nid[maxn];//保存树剖分后的指向子结点的边对应的新编号 14 int nval[maxn];//记录所指向的子结点i新编号对应边的边权,用以建立线段树 15 int oid[maxn];//保存新编号对应在剖分的树中的所指向的子结点(与nid相反) 16 int cnt = 0;//重编号 17 int val[maxn];//原树中指向子结点i的边的边权值 18 int linkto[maxn];//记录指向的子结点 19 struct EDGE 20 { 21 int from, to,w, next; 22 EDGE(int ff = 0, int tt = 0,int ww=0, int nn = 0) :from(ff), to(tt),w(ww), next(nn) {} 23 }edge[maxn * 2]; 24 int Head[maxn], totedge = 0; 25 void addEdge(int from, int to,int w) 26 { 27 edge[totedge] = EDGE(from, to, w,Head[from]); 28 Head[from] = totedge++; 29 edge[totedge] = EDGE(to, from,w, Head[to]); 30 Head[to] = totedge++; 31 } 32 int treeroot = 1; 33 void INIT() 34 { 35 memset(Head, -1, sizeof(Head)); 36 totedge = 0; 37 38 memset(son, -1, sizeof(son)); 39 memset(siz, 0, sizeof(siz)); 40 memset(father, 0, sizeof(father)); 41 memset(top, 0, sizeof(top)); 42 memset(dep, 0, sizeof(dep)); 43 cnt = 0; 44 } 45 46 void dfs1(int u, int fa, int layer) 47 { 48 dep[u] = layer; 49 father[u] = fa; 50 siz[u] = 1; 51 for (int i = Head[u]; i != -1; i = edge[i].next) 52 { 53 int v = edge[i].to; 54 if (v != fa) 55 { 56 dfs1(v, u, layer + 1); 57 siz[u] += siz[v]; 58 linkto[i / 2 + 1] = v; 59 val[v] = edge[i].w; 60 if (son[u] == -1 || siz[v] > siz[son[u]]) 61 { 62 son[u] = v; 63 } 64 } 65 } 66 } 67 68 void dfs2(int u, int Hson) 69 {//Hson,重儿子 70 top[u] = Hson; 71 if (u != treeroot) 72 { 73 nid[u] = ++cnt; 74 oid[cnt] = u; 75 nval[cnt] = val[u]; 76 } 77 if (son[u] == -1) return; 78 dfs2(son[u], Hson);//先将当前重链重编号 79 for (int i = Head[u]; i != -1; i = edge[i].next) 80 {//对不在重链上的点,自己作为子树的重链起点重编号 81 int v = edge[i].to; 82 if (v != son[u] && v != father[u]) dfs2(v, v); 83 } 84 } 85 /*-------线段树·启————*/ 86 struct treenode 87 { 88 int l, r; 89 long long v, tmp; 90 treenode(int ll = 0, int rr = 0, long long vv = 0, long long tt = 0) :l(ll), r(rr), v(vv), tmp(tt) {} 91 }tree[maxn * 4]; 92 93 void BuildTree(int root, int l, int r) 94 { 95 tree[root].l = l, tree[root].r = r; 96 tree[root].tmp = 0; 97 if (l == r) 98 { 99 tree[root].v = nval[l]; 100 return; 101 } 102 int mid = (l + r) / 2; 103 BuildTree(root * 2, l, mid); 104 BuildTree(root * 2 + 1, mid + 1, r); 105 tree[root].v = tree[root * 2].v + tree[root * 2 + 1].v; 106 } 107 void Pushdown(int root) 108 { 109 int lson = root * 2, rson = root * 2 + 1; 110 if (tree[root].tmp) 111 { 112 tree[lson].v = (tree[lson].r - tree[lson].l + 1)*tree[root].tmp; 113 tree[rson].v = (tree[rson].r - tree[rson].l + 1)*tree[root].tmp; 114 tree[lson].tmp = tree[root].tmp; 115 tree[rson].tmp = tree[root].tmp; 116 tree[root].tmp = 0; 117 } 118 } 119 void PushUp(int root) 120 { 121 tree[root].v = tree[root * 2].v + tree[root * 2 + 1].v; 122 } 123 void Update(int root, int l, int r, int add) 124 { 125 if (tree[root].r<l || tree[root].l>r) return; 126 if (l <= tree[root].l&&tree[root].r <= r) 127 { 128 tree[root].tmp = add; 129 tree[root].v = add*(tree[root].r-tree[root].l+1); 130 return; 131 } 132 Pushdown(root); 133 int mid = (tree[root].r + tree[root].l) / 2; 134 if (l <= mid)Update(root * 2, l, r, add); 135 if (r>mid)Update(root * 2 + 1, l, r, add); 136 PushUp(root); 137 } 138 139 long long Query(int root, int l, int r) 140 { 141 if (tree[root].r<l || tree[root].l>r) return 0; 142 if (l <= tree[root].l&&tree[root].r <= r) 143 { 144 return tree[root].v; 145 } 146 Pushdown(root); 147 long long tsum = Query(root * 2, l, r) + Query(root * 2 + 1, l, r); 148 PushUp(root); 149 return tsum; 150 } 151 /*-------线段树·终————*/ 152 153 long long Query_length(int x, int y) 154 {//查询x到y路径上边权和 155 int fx = top[x], fy = top[y]; 156 long long ans = 0; 157 while (fx != fy) 158 { 159 if (dep[fx] > dep[fy]) 160 { 161 int id1 = nid[fx],id2=nid[x]; 162 ans += Query(1, id1, id2); 163 x = father[fx]; 164 fx = top[x]; 165 } 166 else 167 { 168 int id1 = nid[fy], id2 = nid[y]; 169 ans += Query(1, id1, id2); 170 y = father[fy]; 171 fy = top[y]; 172 } 173 } 174 if (x != y) 175 { 176 if (dep[x] > dep[y]) 177 { 178 int id1 = nid[son[y]], id2 = nid[x]; 179 ans += Query(1, id1, id2); 180 } 181 else 182 { 183 int id1 = nid[son[x]], id2 = nid[y]; 184 ans += Query(1, id1, id2); 185 } 186 } 187 return ans; 188 } 189 void Update_path(int x, int y, int add) 190 {//将x到y路径上所有边的值都加上或修改为add 191 int fx = top[x], fy = top[y]; 192 while (fx != fy) 193 { 194 if (dep[fx] >= dep[fy]) 195 { 196 Update(1, nid[fx], nid[x], add); 197 x = father[fx]; 198 fx = top[x]; 199 } 200 else 201 { 202 Update(1, nid[fy], nid[y], add); 203 y = father[fy]; 204 fy = top[y]; 205 } 206 } 207 if (x != y) 208 { 209 if (dep[x] < dep[y]) Update(1, nid[son[x]], nid[y], add); 210 else Update(1, nid[son[y]], nid[x], add); 211 } 212 } 213 /*-------树链剖分·终-------*/ 214 215 int main() 216 { 217 int n, q, s; 218 while (~scanf("%d%d%d", &n, &q, &s)) 219 { 220 INIT(); 221 for (int i = 1; i < n; i++) 222 { 223 int u, v, w; 224 scanf("%d%d%d", &u, &v, &w); 225 addEdge(u, v, w); 226 } 227 dfs1(1,1,1); 228 dfs2(1,1); 229 BuildTree(1, 1, cnt); 230 for (int i = 1; i <= q; i++) 231 { 232 int flag; 233 scanf("%d", &flag); 234 if (flag == 0) 235 { 236 int des; 237 scanf("%d", &des); 238 long long ans = Query_length(s, des); 239 s = des; 240 printf("%lld\n", ans); 241 } 242 else 243 { 244 int id, v; 245 scanf("%d%d", &id, &v); 246 int nID = nid[linkto[id]]; 247 Update(1, nID, nID, v); 248 } 249 250 } 251 252 } 253 return 0; 254 }
7、Query on a tree SPOJ - QTREE
题意:有一棵树,每次将一条边的权值修改或者询问u到v路径上的最大边权。
思路:树链剖分+线段树,边权,区间查询+单点更新。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<iostream> 2 #include<cstring> 3 #include<algorithm> 4 #include<cstdio> 5 using namespace std; 6 const int maxn = 10000 + 10; 7 8 /*-------树链剖分·启-------*/ 9 10 int siz[maxn];//size[i]:以i为根的子树结点个数 11 int top[maxn];//保存结点i所在链的顶端结点 12 int son[maxn];//保存i的重儿子 13 int dep[maxn];//保存结点i的层次(深度) 14 int father[maxn];//保存结点i的父亲结点 15 int nid[maxn];//保存树剖分后的指向子结点的边对应的新编号 16 int nval[maxn];//记录所指向的子结点i新编号对应边的边权,用以建立线段树 17 int oid[maxn];//保存新编号对应在剖分的树中的所指向的子结点(与nid相反) 18 int cnt = 0;//重编号 19 int val[maxn];//原树中指向子结点i的边的边权值 20 int linkto[maxn];//记录指向的子结点 21 struct EDGE 22 { 23 int from, to, w, next; 24 EDGE(int ff = 0, int tt = 0, int ww = 0, int nn = 0) :from(ff), to(tt), w(ww), next(nn) {} 25 }edge[maxn * 2]; 26 int Head[maxn], totedge = 0; 27 void addEdge(int from, int to, int w) 28 { 29 edge[totedge] = EDGE(from, to, w, Head[from]); 30 Head[from] = totedge++; 31 edge[totedge] = EDGE(to, from, w, Head[to]); 32 Head[to] = totedge++; 33 } 34 int treeroot = 1; 35 void INIT() 36 { 37 memset(Head, -1, sizeof(Head)); 38 totedge = 0; 39 40 memset(son, -1, sizeof(son)); 41 memset(siz, 0, sizeof(siz)); 42 memset(father, 0, sizeof(father)); 43 memset(top, 0, sizeof(top)); 44 memset(dep, 0, sizeof(dep)); 45 cnt = 0; 46 } 47 48 void dfs1(int u, int fa, int layer) 49 { 50 dep[u] = layer; 51 father[u] = fa; 52 siz[u] = 1; 53 for (int i = Head[u]; i != -1; i = edge[i].next) 54 { 55 int v = edge[i].to; 56 if (v != fa) 57 { 58 dfs1(v, u, layer + 1); 59 siz[u] += siz[v]; 60 linkto[i / 2 + 1] = v; 61 val[v] = edge[i].w; 62 if (son[u] == -1 || siz[v] > siz[son[u]]) 63 { 64 son[u] = v; 65 } 66 } 67 } 68 } 69 70 void dfs2(int u, int Hson) 71 {//Hson,重儿子 72 top[u] = Hson; 73 if (u != treeroot) 74 { 75 nid[u] = ++cnt; 76 oid[cnt] = u; 77 nval[cnt] = val[u]; 78 } 79 if (son[u] == -1) return; 80 dfs2(son[u], Hson);//先将当前重链重编号 81 for (int i = Head[u]; i != -1; i = edge[i].next) 82 {//对不在重链上的点,自己作为子树的重链起点重编号 83 int v = edge[i].to; 84 if (v != son[u] && v != father[u]) dfs2(v, v); 85 } 86 } 87 /*-------线段树·启————*/ 88 struct treenode 89 { 90 int l, r; 91 long long v, tmp; 92 treenode(int ll = 0, int rr = 0, long long vv = 0, long long tt = 0) :l(ll), r(rr), v(vv), tmp(tt) {} 93 }tree[maxn * 4]; 94 95 void PushUp(int root) 96 { 97 tree[root].v = max(tree[root * 2].v, tree[root * 2 + 1].v); 98 } 99 100 void BuildTree(int root, int l, int r) 101 { 102 tree[root].l = l, tree[root].r = r; 103 tree[root].tmp = 0; 104 if (l == r) 105 { 106 tree[root].v = nval[l]; 107 return; 108 } 109 int mid = (l + r) / 2; 110 BuildTree(root * 2, l, mid); 111 BuildTree(root * 2 + 1, mid + 1, r); 112 tree[root].v = max(tree[root * 2].v, tree[root * 2 + 1].v); 113 } 114 void PushDown(int root) 115 { 116 int lson = root * 2, rson = root * 2 + 1; 117 if (tree[root].tmp) 118 { 119 tree[lson].v = (tree[lson].r - tree[lson].l + 1)*tree[root].tmp; 120 tree[rson].v = (tree[rson].r - tree[rson].l + 1)*tree[root].tmp; 121 tree[lson].tmp = tree[root].tmp; 122 tree[rson].tmp = tree[root].tmp; 123 tree[root].tmp = 0; 124 } 125 } 126 127 void Update(int root, int l, int r, int add) 128 { 129 if (tree[root].r<l || tree[root].l>r) return; 130 if (l <= tree[root].l&&tree[root].r <= r) 131 { 132 tree[root].tmp = add; 133 tree[root].v = add * (tree[root].r - tree[root].l + 1); 134 return; 135 } 136 PushDown(root); 137 int mid = (tree[root].r + tree[root].l) / 2; 138 if (l <= mid)Update(root * 2, l, r, add); 139 if (r>mid)Update(root * 2 + 1, l, r, add); 140 PushUp(root); 141 } 142 143 long long Query(int root, int l, int r) 144 { 145 if (tree[root].r<l || tree[root].l>r) return 0; 146 if (l <= tree[root].l&&tree[root].r <= r) 147 { 148 return tree[root].v; 149 } 150 PushDown(root); 151 long long ans = 0, tmp1, tmp2; 152 bool flag = false; 153 int mid = (tree[root].l + tree[root].r) / 2; 154 if (l <= mid) tmp1 = Query(root * 2, l, r), flag = true; 155 if (r > mid) tmp2 = Query(root * 2 + 1, l, r); 156 PushUp(root); 157 if (flag) ans = max(tmp1, tmp2); 158 else ans = tmp2; 159 return ans; 160 } 161 /*-------线段树·终————*/ 162 163 long long Query_length(int x, int y) 164 {//查询x到y路径上最大边权 165 int fx = top[x], fy = top[y]; 166 long long ans = 0; 167 bool flag = false; 168 while (fx != fy) 169 { 170 if (dep[fx] > dep[fy]) 171 { 172 173 int id1 = nid[fx], id2 = nid[x]; 174 long long tmp = Query(1, id1, id2); 175 x = father[fx]; 176 fx = top[x]; 177 if (!flag) ans = tmp; 178 else ans = max(ans, tmp); 179 flag = true; 180 } 181 else 182 { 183 int id1 = nid[fy], id2 = nid[y]; 184 long long tmp = Query(1, id1, id2); 185 y = father[fy]; 186 fy = top[y]; 187 if (!flag) ans = tmp; 188 else ans = max(ans, tmp); 189 flag = true; 190 } 191 } 192 if (x != y) 193 { 194 if (dep[x] > dep[y]) 195 { 196 197 int id1 = nid[son[y]], id2 = nid[x]; 198 long long tmp = Query(1, id1, id2); 199 if (!flag) ans = tmp; 200 else ans = max(ans, tmp); 201 flag = true; 202 } 203 else 204 { 205 int id1 = nid[son[x]], id2 = nid[y]; 206 long long tmp = Query(1, id1, id2); 207 if (!flag) ans = tmp; 208 else ans = max(ans, tmp); 209 flag = true; 210 } 211 } 212 return ans; 213 } 214 void Update_path(int x, int y, int add) 215 {//将x到y路径上所有边的值都加上或修改为add 216 int fx = top[x], fy = top[y]; 217 while (fx != fy) 218 { 219 if (dep[fx] >= dep[fy]) 220 { 221 Update(1, nid[fx], nid[x], add); 222 x = father[fx]; 223 fx = top[x]; 224 } 225 else 226 { 227 Update(1, nid[fy], nid[y], add); 228 y = father[fy]; 229 fy = top[y]; 230 } 231 } 232 if (x != y) 233 { 234 if (dep[x] < dep[y]) Update(1, nid[son[x]], nid[y], add); 235 else Update(1, nid[son[y]], nid[x], add); 236 } 237 } 238 /*-------树链剖分·终-------*/ 239 240 int main() 241 { 242 int t; 243 scanf("%d", &t); 244 int n, m; 245 while (t--) 246 { 247 INIT(); 248 scanf("%d", &n); 249 for (int i = 1; i < n; i++) 250 { 251 int u, v, w; 252 scanf("%d%d%d", &u, &v, &w); 253 addEdge(u, v, w); 254 } 255 dfs1(1, 1, 1); 256 dfs2(1, 1); 257 BuildTree(1, 1, cnt); 258 char s[10]; 259 while (true) 260 { 261 scanf("%s", s); 262 if (s[0] == 'Q') 263 { 264 int u, v; 265 scanf("%d%d", &u, &v); 266 long long ans = Query_length(u, v); 267 printf("%lld\n", ans); 268 } 269 else if (s[0] == 'C') 270 { 271 int id, v; 272 scanf("%d%d", &id, &v); 273 int nID = nid[linkto[id]]; 274 Update(1, nID, nID, v); 275 } 276 else 277 { 278 break; 279 } 280 } 281 } 282 return 0; 283 }
8、POJ - 3237 Tree
题意:有一棵树,每次改变一条边的边权,或将一条路径上所有边权取反,或者求一条路径上边权的最大值。
思路:树链剖分+线段树,边权。主要练习取反。记录一个错误:建树时忘记向上更新最小值,只更新了最大值,调了好久没发现。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<iostream> 2 #include<cstring> 3 #include<algorithm> 4 #include<cstdio> 5 using namespace std; 6 const int maxn = 10000+ 10; 7 8 /*-------树链剖分·启-------*/ 9 10 int siz[maxn];//size[i]:以i为根的子树结点个数 11 int top[maxn];//保存结点i所在链的顶端结点 12 int son[maxn];//保存i的重儿子 13 int dep[maxn];//保存结点i的层次(深度) 14 int father[maxn];//保存结点i的父亲结点 15 int nid[maxn];//保存树剖分后的指向子结点的边对应的新编号 16 int nval[maxn];//记录所指向的子结点i新编号对应边的边权,用以建立线段树 17 int oid[maxn];//保存新编号对应在剖分的树中的所指向的子结点(与nid相反) 18 int cnt = 0;//重编号 19 int val[maxn];//原树中指向子结点i的边的边权值 20 int linkto[maxn];//记录指向的子结点 21 struct EDGE 22 { 23 int from, to, w, next; 24 EDGE(int ff = 0, int tt = 0, int ww = 0, int nn = 0) :from(ff), to(tt), w(ww), next(nn) {} 25 }edge[maxn * 2]; 26 int Head[maxn], totedge = 0; 27 void addEdge(int from, int to, int w) 28 { 29 edge[totedge] = EDGE(from, to, w, Head[from]); 30 Head[from] = totedge++; 31 edge[totedge] = EDGE(to, from, w, Head[to]); 32 Head[to] = totedge++; 33 } 34 int treeroot = 1; 35 void INIT() 36 { 37 memset(Head, -1, sizeof(Head)); 38 totedge = 0; 39 40 memset(son, -1, sizeof(son)); 41 cnt = 0; 42 } 43 44 void dfs1(int u, int fa, int layer) 45 { 46 dep[u] = layer; 47 father[u] = fa; 48 siz[u] = 1; 49 for (int i = Head[u]; i != -1; i = edge[i].next) 50 { 51 int v = edge[i].to; 52 if (v != fa) 53 { 54 dfs1(v, u, layer + 1); 55 siz[u] += siz[v]; 56 linkto[i / 2 + 1] = v; 57 val[v] = edge[i].w; 58 if (son[u] == -1 || siz[v] > siz[son[u]]) 59 { 60 son[u] = v; 61 } 62 } 63 } 64 } 65 66 void dfs2(int u, int Hson) 67 {//Hson,重儿子 68 top[u] = Hson; 69 if (u != treeroot) 70 { 71 nid[u] = ++cnt; 72 oid[cnt] = u; 73 nval[cnt] = val[u]; 74 } 75 if (son[u] == -1) return; 76 dfs2(son[u], Hson);//先将当前重链重编号 77 for (int i = Head[u]; i != -1; i = edge[i].next) 78 {//对不在重链上的点,自己作为子树的重链起点重编号 79 int v = edge[i].to; 80 if (v != son[u] && v != father[u]) dfs2(v, v); 81 } 82 } 83 /*-------线段树·启————*/ 84 struct treenode 85 { 86 int l, r; 87 long long maxv, minv; 88 int delay; 89 treenode(int ll = 0, int rr = 0, long long vv = 0, long long mv = 0, int tt = 0) :l(ll), r(rr), maxv(vv), minv(mv), delay(tt) {} 90 }tree[maxn * 4]; 91 92 void PushUp(int root) 93 { 94 tree[root].maxv = max(tree[root * 2].maxv, tree[root * 2 + 1].maxv); 95 tree[root].minv = min(tree[root * 2].minv, tree[root * 2 + 1].minv); 96 } 97 98 void BuildTree(int root, int l, int r) 99 { 100 tree[root].l = l, tree[root].r = r; 101 tree[root].delay = 0; 102 if (l == r) 103 { 104 tree[root].maxv = tree[root].minv = nval[l]; 105 return; 106 } 107 int mid = (l + r) / 2; 108 BuildTree(root * 2, l, mid); 109 BuildTree(root * 2 + 1, mid + 1, r); 110 PushUp(root); 111 } 112 void PushDown(int root) 113 { 114 int lson = root * 2, rson = root * 2 + 1; 115 if (tree[root].delay) 116 { 117 swap(tree[lson].maxv, tree[lson].minv); 118 tree[lson].maxv = -tree[lson].maxv, tree[lson].minv = -tree[lson].minv; 119 swap(tree[rson].maxv, tree[rson].minv); 120 tree[rson].maxv = -tree[rson].maxv, tree[rson].minv = -tree[rson].minv; 121 tree[lson].delay ^= 1; 122 tree[rson].delay ^= 1; 123 tree[root].delay = 0; 124 } 125 } 126 127 void Update(int root, int l, int r, int v) 128 {//单点修改 129 if (tree[root].r<l || tree[root].l>r) return; 130 if (tree[root].l == tree[root].r) 131 { 132 tree[root].maxv = tree[root].minv = v; 133 tree[root].delay = 0; 134 return; 135 } 136 PushDown(root); 137 int mid = (tree[root].r + tree[root].l) / 2; 138 if (l <= mid)Update(root * 2, l, r, v); 139 if (r > mid)Update(root * 2 + 1, l, r, v); 140 PushUp(root); 141 } 142 void Update_Neg(int root, int l, int r) 143 {//取反 144 if (tree[root].r<l || tree[root].l>r) return; 145 if (l <= tree[root].l&&tree[root].r <= r) 146 { 147 tree[root].delay ^= 1; 148 swap(tree[root].maxv, tree[root].minv); 149 tree[root].maxv = -tree[root].maxv, tree[root].minv = -tree[root].minv; 150 return; 151 } 152 PushDown(root); 153 int mid = (tree[root].r + tree[root].l) / 2; 154 if (l <= mid)Update_Neg(root * 2, l, r); 155 if (r > mid)Update_Neg(root * 2 + 1, l, r); 156 PushUp(root); 157 } 158 159 long long Query(int root, int l, int r) 160 { 161 if (tree[root].r<l || tree[root].l>r) return 0; 162 if (l <= tree[root].l&&tree[root].r <= r) 163 { 164 return tree[root].maxv; 165 } 166 PushDown(root); 167 long long ans = 0, tmp1, tmp2; 168 bool flag1 = false, flag2 = false; 169 int mid = (tree[root].l + tree[root].r) / 2; 170 if (l <= mid) tmp1 = Query(root * 2, l, r), flag1 = true; 171 if (r > mid) tmp2 = Query(root * 2 + 1, l, r), flag2 = true; 172 PushUp(root); 173 if (flag1&&flag2) ans = max(tmp1, tmp2); 174 else if (flag2)ans = tmp2; 175 else ans = tmp1; 176 return ans; 177 } 178 /*-------线段树·终————*/ 179 180 long long Query_length(int x, int y) 181 {//查询x到y路径上最大边权 182 int fx = top[x], fy = top[y]; 183 long long ans = 0; 184 bool flag = false; 185 while (fx != fy) 186 { 187 if (dep[fx] > dep[fy]) 188 { 189 190 int id1 = nid[fx], id2 = nid[x]; 191 long long tmp = Query(1, id1, id2); 192 x = father[fx]; 193 fx = top[x]; 194 if (!flag) ans = tmp; 195 else ans = max(ans, tmp); 196 flag = true; 197 } 198 else 199 { 200 int id1 = nid[fy], id2 = nid[y]; 201 long long tmp = Query(1, id1, id2); 202 y = father[fy]; 203 fy = top[y]; 204 if (!flag) ans = tmp; 205 else ans = max(ans, tmp); 206 flag = true; 207 } 208 } 209 if (x != y) 210 { 211 if (dep[x] > dep[y]) 212 { 213 214 int id1 = nid[son[y]], id2 = nid[x]; 215 long long tmp = Query(1, id1, id2); 216 if (!flag) ans = tmp; 217 else ans = max(ans, tmp); 218 flag = true; 219 } 220 else 221 { 222 int id1 = nid[son[x]], id2 = nid[y]; 223 long long tmp = Query(1, id1, id2); 224 if (!flag) ans = tmp; 225 else ans = max(ans, tmp); 226 flag = true; 227 } 228 } 229 return ans; 230 } 231 void Update_path(int x, int y) 232 {//将x到y路径上所有边的值都取反 233 int fx = top[x], fy = top[y]; 234 while (fx != fy) 235 { 236 if (dep[fx] >= dep[fy]) 237 { 238 Update_Neg(1, nid[fx], nid[x]); 239 x = father[fx]; 240 fx = top[x]; 241 } 242 else 243 { 244 Update_Neg(1, nid[fy], nid[y]); 245 y = father[fy]; 246 fy = top[y]; 247 } 248 } 249 if (x != y) 250 { 251 if (dep[x] < dep[y]) Update_Neg(1, nid[son[x]], nid[y]); 252 else Update_Neg(1, nid[son[y]], nid[x]); 253 } 254 } 255 /*-------树链剖分·终-------*/ 256 257 int main() 258 { 259 int t; 260 scanf("%d", &t); 261 int n, m; 262 while (t--) 263 { 264 INIT(); 265 scanf("%d", &n); 266 for (int i = 1; i < n; i++) 267 { 268 int u, v, w; 269 scanf("%d%d%d", &u, &v, &w); 270 addEdge(u, v, w); 271 } 272 dfs1(1, 1, 1); 273 dfs2(1, 1); 274 BuildTree(1, 1, cnt); 275 char s[10]; 276 while (true) 277 { 278 scanf("%s", s); 279 if (s[0] == 'Q') 280 { 281 int u, v; 282 scanf("%d%d", &u, &v); 283 long long ans = Query_length(u, v); 284 printf("%lld\n", ans); 285 } 286 else if (s[0] == 'C') 287 { 288 int id, v; 289 scanf("%d%d", &id, &v); 290 int nID = nid[linkto[id]]; 291 Update(1, nID, nID, v); 292 } 293 else if (s[0] == 'N') 294 { 295 int u, v; 296 scanf("%d%d", &u, &v); 297 Update_path(u, v); 298 } 299 else 300 { 301 break; 302 } 303 } 304 } 305 return 0; 306 }