树链剖分

1、hdu 3966 Aragorn's Story

  题意:敌人有n个帐篷,每个帐篷有初始人数,两两之间只有一条路径。现在进行q次操作,可以把c1到c2路径上的所有帐篷人数都加上或减去一个值,或者询问某个帐篷当前人数。

  思路:树链剖分模板题,线段树,点权,区间更新,单点查询。

  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 }
View Code

2、HYSBZ - 2243 染色

  题意:

给定一棵有n个节点的无根树和m个操作,操作有2类:
1、将节点a到节点b路径上所有点都染成颜色c;
2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),
如“112221”由3段组成:“11”、“222”和“1”。
请你写一个程序依次完成这m个操作。
  思路:
树链剖分+线段树,点权,区间更新+区间查询,分段。线段树应当记录[l,r]中颜色段数量以及左右边界颜色。
  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 }
View Code

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本身

  思路:树链剖分+线段树,点权,单点更新+区间查询。线段树维护区间和和最大值。

  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 }
View Code

4、FZU - 2082 过路费

  题意:有n座城市,由n-1条路相连通,使得任意两座城市之间可达。每条路有过路费,要交过路费才能通过。每条路的过路费经常会更新,现问你,当前情况下,从城市a到城市b最少要花多少过路费。

  思路:树链剖分+线段树,边权,单点更新+区间查询。注意对边进行编号,以及一些辅助数组记录边指向的结点、边权。

  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 }
View Code

 5、LightOJ - 1348 Aladdin and the Return Journey

  题意:有一棵树,每次更新一个点的权值或者查询u到v路径上所有结点权值之和。

  思路:树链剖分+线段树,点权,单点更新和区间查询。

  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 }
View Code

 6、Housewife Wind POJ - 2763

  题意:有一个小镇,有n户人家和n-1条路(树),有一位母亲要去接孩子,起点位于s。两种操作:修改通过某一条路的时间;母亲要从当前位置到达u的位置接孩子,求时间。

  思路:树链剖分+线段树,边权,区间查询+单点更新。

  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 }
View Code

7、Query on a tree SPOJ - QTREE

   题意:有一棵树,每次将一条边的权值修改或者询问u到v路径上的最大边权。

  思路:树链剖分+线段树,边权,区间查询+单点更新。

  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 }
View Code

 8、POJ - 3237 Tree 

  题意:有一棵树,每次改变一条边的边权,或将一条路径上所有边权取反,或者求一条路径上边权的最大值。

  思路:树链剖分+线段树,边权。主要练习取反。记录一个错误:建树时忘记向上更新最小值,只更新了最大值,调了好久没发现。

  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 }
View Code

 

 

posted @ 2018-07-24 10:25  萌萌的美男子  阅读(183)  评论(0编辑  收藏  举报