一篇自己都看不懂的树链剖分学习笔记

树链剖分是一个比较好理解的数据结构,码量不是很大(如果你发现你写的很多,那么一定是线段树的锅)

PS:树链剖分默认为重链剖分,长链剖分和实链剖分(LCT)以后有时间再写

One.树链剖分用来干啥

树链剖分的基本应用是对一段路径上或者一棵子树的点的点权进行修改,并且对路径或者子树内的点权进行查询操作。树链剖分本身的复杂度为$O(nlogn)$,但是因为它经常要与线段树、树状数组等$log$数据结构共用,所以一般需要用到树链剖分的问题的时间复杂度为$O(nlog^2n)$

Two.前置知识

会dfs序、会线段树,要求还是很低的

Three.理论 

先约定几个符号:

$size_i$:以点$i$为根的子树的大小

$dfn_i$:点$i$在$dfs$时获得的序号(即点$i$的$dfs$序)

$dep_i$:点$i$的深度

$top_i$:等会儿解释

数据结构的名字是树链剖分,也就是把一棵树剖成一条一条的链进行维护。其中最讲究的还是如何剖链。

$For\,example$,对于下面这棵树,我们对它进行剖分

在树链剖分的模式下,我们标记每一个点与其$size$最大的儿子(称其为重儿子)的边(如果没有儿子就不管),因为这个儿子是最重的,所以称它为重边,而其他没有标记的边为轻边,如果有多个$size$同样最大的儿子,就随机标记一条。

如果将重边标红,那么上面的那棵树就会变成下面这样:

可以发现重边相连形成了一些重链(这棵树上有$2$条重链)

关于轻边和重链有一个很重要的性质:

每一个点到根所经过的轻边和重链的数量不超过$logn$条(其中$n$为点数)

证明:对于轻边,考虑子树大小。假如从$i$号点通过一条轻边跳到了其父亲$j$号点,那么意味着至少存在一个不为$i$的$j$的儿子$k$满足$size_k \geq size_i$,那么$size_j \geq size_i \times 2$,也就是说从$i$走到$j$,子树大小至少翻倍,那么经过$x$条轻边到达的点的子树大小至少为$2^x$,所以$2^x \leq n$,即$x \leq logn$。因为重链是被轻边分开的,所以重链的数量也不会超过$logn$条。

这一个结论意味着如果我们可以将重链上的操作变为$O(1)$或者$O(logn)$的话,时间复杂度就会十分优秀。

在区间修改之前,考虑一个问题:如何在树链剖分的模式下求$LCA$

考虑将每一个点所在的重链中深度最浅的点,也就是链顶$top$记下来,就像下面这样

(这里手滑了,$top_8$应该等于$8$)

以发现:我们可以通过$top\,O(1)$地跳一条重链了!那么根据上面的分析,我们求$LCA$的复杂度也就是$O(logn)$了,复杂度与倍增一致,但是树链剖分常数更小(因为实际上很难跳满$logn$条链)

总结一下求$x,y$两点$LCA$的操作步骤:

1、获得$top_x$和$top_y$

2、如果$top_x==top_y$转步骤5,否则转步骤3

3、如果$dep_{top_x}<dep_{top_y}$,交换$x$和$y$

4、令$x=fa_{top_x}$,跳过$x$所在的重链和重链顶的轻边,转步骤1

5、如果$dep_x<dep_y$,则$LCA(x,y)=x$,否则为$y$

不是很好理解的是步骤3,为什么要比较$top$的$dep$的大小而不是本身的$dep$的大小?留给读者自证

会跳LCA了,接下来考虑路径和子树的修改。

对于树上的区间修改我们常用$DFS$序+区间修改数据结构进行配合,在树链剖分中也是一样的,但是因为我们需要优化重链上的修改,所以$DFS$的顺序十分重要。

我们每一次$DFS$到一个点,优先向其重儿子$DFS$,这样可以得到一个特别的$dfn$序:

可以发现一条重链上的$dfn$是连续的,这意味着我们在对一条路径做修改的时候,在上面求两点$LCA$的过程中对跳过的重链的部分进行区间修改就可以了,查询同理。使用线段树、树状数组等数据结构可以对这一些修改和查询进行维护。

而子树的$dfn$序显然也是连续的。

那么我们最重要的修改和查询问题就解决了o(* ̄▽ ̄*)ブ

Four.实现的一些细节

一般树链剖分的实现是两个$dfs$:

第一个$dfs$处理$dep$、$fa$、$size$和重儿子

第二个$dfs$处理$top$和$dfn$

Five.一个例题

例题当然要是Luogu的树链剖分模板题

其实操作就是上面的操作qwq

  1 #include<bits/stdc++.h>
  2 #define MAXN 100001 
  3 using namespace std;
  4 inline int read(){
  5     int a = 0;
  6     char c = getchar();
  7     while(!isdigit(c))
  8         c = getchar();
  9     while(isdigit(c)){
 10         a = (a << 3) + (a << 1) + (c ^ '0');
 11         c = getchar();
 12     }
 13     return a;
 14 }
 15 
 16 int forOutput[12];
 17 inline void print(int a){
 18     int dirN = 0;
 19     while(a){
 20         forOutput[dirN++] = a % 10;
 21         a /= 10;
 22     }
 23     if(dirN == 0)
 24         putchar('0');
 25     while(dirN)
 26         putchar('0' + forOutput[--dirN]);
 27     putchar('\n');
 28 }
 29 
 30 struct node{
 31     int l , r , sum , mark;
 32 }SegTree[MAXN << 2];
 33 struct Edge{
 34     int end , upEd;
 35 }Ed[MAXN << 1];
 36 int N , M , R , P , ts , cntEd;
 37 int fa[MAXN] , size[MAXN] , son[MAXN] , ind[MAXN] , rk[MAXN] , depth[MAXN] , top[MAXN] , val[MAXN] , head[MAXN] , maxInd[MAXN];
 38 
 39 inline int max(int a , int b){
 40     return a > b ? a : b;
 41 }
 42 
 43 //加边
 44 inline void addEd(int a , int b){
 45     Ed[++cntEd].end = b;
 46     Ed[cntEd].upEd = head[a];
 47     head[a] = cntEd;
 48 }
 49 
 50 //第一个dfs,处理size、son、fa和dep
 51 void dfs1(int dir , int dep , int father){
 52     depth[dir] = dep;
 53     fa[dir] = father;
 54     size[dir] = 1;
 55     for(int i = head[dir] ; i ; i = Ed[i].upEd)
 56         if(Ed[i].end != father){
 57             dfs1(Ed[i].end , dep + 1 , dir);
 58             size[dir] += size[Ed[i].end];
 59             if(size[son[dir]] < size[Ed[i].end])
 60                 son[dir] = Ed[i].end;
 61         }
 62 }
 63 
 64 //第二个dfs,处理top和ind
 65 //注意到那个rk了吗?rk[i]表示的是dfs序为i的点在原树中的编号,这样在线段树的初始化部分就可以直接带入点权了。
 66 void dfs2(int dir , int t){
 67     top[dir] = t;
 68     maxInd[dir] = ind[dir] = ++ts;
 69     rk[ts] = dir;
 70     if(!son[dir])
 71         return;
 72     dfs2(son[dir] , t);
 73     maxInd[dir] = max(maxInd[dir] , maxInd[son[dir]]);
 74     for(int i = head[dir] ; i ; i = Ed[i].upEd)
 75         if(Ed[i].end != son[dir] && Ed[i].end != fa[dir]){
 76             dfs2(Ed[i].end , Ed[i].end);
 77             maxInd[dir] = max(maxInd[dir] , maxInd[Ed[i].end]);
 78         }
 79 }
 80 
 81 //线段树更新信息
 82 inline void pushup(int dir){
 83     SegTree[dir].sum = (SegTree[dir << 1].sum + SegTree[dir << 1 | 1].sum) % P;
 84 }
 85 
 86 //线段树下放标记
 87 inline void pushdown(int dir){
 88     if(SegTree[dir].mark){
 89         SegTree[dir << 1].sum = (SegTree[dir << 1].sum + (SegTree[dir << 1].r - SegTree[dir << 1].l + 1) * SegTree[dir].mark) % P;
 90         SegTree[dir << 1 | 1].sum = (SegTree[dir << 1 | 1].sum + (SegTree[dir << 1 | 1].r - SegTree[dir << 1 | 1].l + 1) * SegTree[dir].mark) % P;
 91         SegTree[dir << 1].mark = (SegTree[dir << 1].mark + SegTree[dir].mark) % P;
 92         SegTree[dir << 1 | 1].mark = (SegTree[dir << 1 | 1].mark + SegTree[dir].mark) % P;
 93         SegTree[dir].mark = 0;
 94     }
 95 }
 96 
 97 //线段树初始化
 98 void init(int dir , int l , int r){
 99     SegTree[dir].l = l;
100     SegTree[dir].r = r;
101     if(l == r)
102     //rk在这里起作用!
103         SegTree[dir].sum = val[rk[l]] % P;
104     else{
105         init(dir << 1 , l , l + r >> 1);
106         init(dir << 1 | 1 , (l + r >> 1) + 1 , r);
107         pushup(dir);
108     }
109 }
110 
111 //线段树修改
112 void change(int dir , int l , int r , int mark){
113     if(SegTree[dir].l >= l && SegTree[dir].r <= r){
114         SegTree[dir].mark = (SegTree[dir].mark + mark) % P;
115         SegTree[dir].sum = (SegTree[dir].sum + (SegTree[dir].r - SegTree[dir].l + 1) * mark) % P;
116         return;
117     }
118     pushdown(dir);
119     if(l <= SegTree[dir].l + SegTree[dir].r >> 1)
120         change(dir << 1 , l , r , mark);
121     if(r > SegTree[dir].l + SegTree[dir].r >> 1)
122         change(dir << 1 | 1 , l , r , mark);
123     pushup(dir);
124 }
125 
126 //线段树查询和
127 int getSum(int dir , int l , int r){
128     if(SegTree[dir].l >= l && SegTree[dir].r <= r)
129         return SegTree[dir].sum;
130     pushdown(dir);
131     int sum = 0;
132     if(l <= SegTree[dir].l + SegTree[dir].r >> 1)
133         sum = (sum + getSum(dir << 1 , l , r)) % P;
134     if(r > SegTree[dir].l + SegTree[dir].r >> 1)
135         sum = (sum + getSum(dir << 1 | 1 , l , r)) % P;
136     return sum;
137 }
138 
139 //边跳边修改的路径操作
140 inline void work1(int x , int y , int z){
141     int fx = top[x] , fy = top[y];
142     while(fx != fy){
143         if(depth[fx] >= depth[fy]){
144             //将跳过的重链进行修改,下同
145             change(1 , ind[fx] , ind[x] , z);
146             x = fa[fx];
147             fx = top[x];
148         }
149         else{
150             change(1 , ind[fy] , ind[y] , z);
151             y = fa[fy];
152             fy = top[y];
153         }
154     }
155     //将最后一段修改
156     if(ind[x] <= ind[y])
157         change(1 , ind[x] , ind[y] , z);
158     else
159         change(1 , ind[y] , ind[x] , z);
160 }
161 
162 //边跳边算答案
163 inline int work2(int x , int y){
164     int fx = top[x] , fy = top[y] , sum = 0;
165     while(fx != fy){
166         if(depth[fx] >= depth[fy]){
167             //边跳边加入答案
168             sum = (sum + getSum(1 , ind[fx] , ind[x])) % P;
169             x = fa[fx];
170             fx = top[x];
171         }
172         else{
173             sum = (sum + getSum(1 , ind[fy] , ind[y])) % P;
174             y = fa[fy];
175             fy = top[y];
176         }
177     }
178     //将最后一段算入答案
179     if(ind[x] <= ind[y])
180         sum = (sum + getSum(1 , ind[x] , ind[y])) % P;
181     else
182         sum = (sum + getSum(1 , ind[y] , ind[x])) % P;
183     return sum;
184 }
185 
186 //子树修改与查询
187 void work3(int x , int z){
188     change(1 , ind[x] , maxInd[x] , z);
189 }
190 
191 int work4(int x){
192     return getSum(1 , ind[x] , maxInd[x]);
193 }
194 
195 int main(){
196     N = read();
197     M = read();
198     R = read();
199     P = read();
200     for(int i = 1 ; i <= N ; i++)
201         val[i] = read();
202     for(int i = 1 ; i < N ; i++){
203         int a = read() , b = read();
204         addEd(a , b);
205         addEd(b , a);
206     }
207     dfs1(R , 1 , 0);
208     dfs2(R , R);
209     init(1 , 1 , N);
210     while(M--){
211         int a = read() , b = read() , c , d;
212         switch(a){
213             case 1:
214                 c = read();
215                 d = read();
216                 work1(b , c , d);
217                 break;
218             case 2:
219                 c = read();
220                 print(work2(b , c));
221                 break;
222             case 3:
223                 c = read();
224                 work3(b , c);
225                 break;
226             case 4:
227                 print(work4(b));
228         }
229     }
230     return 0;
231 }            
树剖模板

Six.一些练习题

a.基础

HEOI/TJOI2016 树

  1 #include<bits/stdc++.h>
  2 #define MAXN 100001
  3 using namespace std;
  4 
  5 struct node{
  6     int l , r , maxN;
  7 }Tree[MAXN << 2];
  8 struct head{
  9     int end , upEd;
 10 }Ed[MAXN << 1];
 11 int head[MAXN] , size[MAXN] , son[MAXN] , fa[MAXN] , dep[MAXN];
 12 int ind[MAXN] , rk[MAXN] , top[MAXN] , N , cntEd , ts;
 13 
 14 inline void addEd(int a , int b){
 15     Ed[++cntEd].end = b;
 16     Ed[cntEd].upEd = head[a];
 17     head[a] = cntEd;
 18 }
 19 
 20 void dfs1(int dir , int father){
 21     size[dir] = 1;
 22     dep[dir] = dep[fa[dir] = father] + 1;
 23     for(int i = head[dir] ; i ; i = Ed[i].upEd)
 24         if(!dep[Ed[i].end]){
 25             dfs1(Ed[i].end , dir);
 26             size[dir] += size[Ed[i].end];
 27             if(size[son[dir]] < size[Ed[i].end])
 28                 son[dir] = Ed[i].end;
 29         }
 30 }
 31 
 32 void dfs2(int dir , int t){
 33     top[dir] = t;
 34     rk[ind[dir] = ++ts] = dir;
 35     if(!son[dir])
 36         return;
 37     dfs2(son[dir] , t);
 38     for(int i = head[dir] ; i ; i = Ed[i].upEd)
 39         if(Ed[i].end != son[dir] && Ed[i].end != fa[dir])
 40             dfs2(Ed[i].end , Ed[i].end);
 41 }
 42 
 43 inline int max(int a , int b){
 44     return a > b ? a : b;
 45 }
 46 
 47 void init(int dir , int l , int r){
 48     Tree[dir].l = l;
 49     Tree[dir].r = r;
 50     if(l == r)
 51         Tree[dir].maxN = l == 1;
 52     else{
 53         init(dir << 1 , l , (l + r) >> 1);
 54         init(dir << 1 | 1 , ((l + r) >> 1) + 1 , r);
 55         Tree[dir].maxN = max(Tree[dir << 1].maxN , Tree[dir << 1 | 1].maxN);
 56     }
 57 }
 58 
 59 void change(int dir , int tar){
 60     if(Tree[dir].l == Tree[dir].r){
 61         Tree[dir].maxN = tar;
 62         return;
 63     }
 64     if(tar <= (Tree[dir].l + Tree[dir].r) >> 1)
 65         change(dir << 1 , tar);
 66     else
 67         change(dir << 1 | 1 , tar);
 68     Tree[dir].maxN = max(Tree[dir << 1].maxN , Tree[dir << 1 | 1].maxN);
 69 }
 70 
 71 int findMax(int dir , int l , int r){
 72     if(Tree[dir].l >= l && Tree[dir].r <= r)
 73         return Tree[dir].maxN;
 74     int maxN;
 75     if(r > (Tree[dir].l + Tree[dir].r) >> 1){
 76         maxN = findMax(dir << 1 | 1 , l , r);
 77         if(maxN)
 78             return maxN;
 79     }
 80     if(l <= (Tree[dir].l + Tree[dir].r) >> 1)
 81         return findMax(dir << 1 , l , r);
 82     return 0;
 83 }
 84 
 85 inline int work(int tar){
 86     while(top[tar] != 1){
 87         int maxN = findMax(1 , ind[top[tar]] , ind[tar]);
 88         if(maxN)
 89             return rk[maxN];
 90         tar = fa[top[tar]];
 91     }
 92     return rk[findMax(1 , 1 , ind[tar])];
 93 }
 94 
 95 int main(){
 96     int Q;
 97     cin >> N >> Q;
 98     for(int i = 1 ; i < N ; i++){
 99         int a , b;
100         cin >> a >> b;
101         addEd(a , b);
102         addEd(b , a);
103     }
104     dfs1(1 , 0);
105     dfs2(1 , 1);
106     init(1 , 1 , N);
107     while(Q--){
108         char c;
109         int a;
110         cin >> c >> a;
111         if(c == 'C')
112             change(1 , ind[a]);
113         else
114             cout << work(a) << endl;
115     }
116     return 0;
117 }

HAOI2015 树上操作

  1 #include<bits/stdc++.h>
  2 #define ll long long
  3 #define MAXN 100001
  4 using namespace std;
  5 inline ll read(){
  6     ll a = 0;
  7     bool f = 0;
  8     char c = getchar();
  9     while(!isdigit(c)){
 10         if(c == '-')
 11             f = 1;
 12         c = getchar();
 13     }
 14     while(isdigit(c)){
 15         a = (a << 3) + (a << 1) + (c ^ '0');
 16         c = getchar();
 17     }
 18     return f ? -a : a;
 19 }
 20 
 21 ll forOutput[25];
 22 inline void prll(ll a){
 23     ll dirN = 0;
 24     if(a < 0){
 25         putchar('-');
 26         a = -a;
 27     }
 28     while(a){
 29         forOutput[dirN++] = a % 10;
 30         a /= 10;
 31     }
 32     if(dirN == 0)
 33         putchar('0');
 34     while(dirN)
 35         putchar('0' + forOutput[--dirN]);
 36     putchar('\n');
 37 }
 38 
 39 struct node{
 40     ll l , r , sum , mark;
 41 }SegTree[MAXN << 2];
 42 struct Edge{
 43     ll end , upEd;
 44 }Ed[MAXN << 1];
 45 ll size[MAXN] , val[MAXN] , head[MAXN] , son[MAXN] , fa[MAXN] , top[MAXN] , ind[MAXN] , rk[MAXN] , depth[MAXN];
 46 ll N , cntEd , M , ts;
 47 
 48 inline void addEd(ll a , ll b){
 49     Ed[++cntEd].end = b;
 50     Ed[cntEd].upEd = head[a];
 51     head[a] = cntEd;
 52 }
 53 
 54 void dfs1(ll dir , ll dep , ll father){
 55     depth[dir] = dep;
 56     fa[dir] = father;
 57     size[dir] = 1;
 58     for(ll i = head[dir] ; i ; i = Ed[i].upEd)    
 59         if(Ed[i].end != father){
 60             dfs1(Ed[i].end , dep + 1 , dir);
 61             size[dir] += size[Ed[i].end];
 62             if(size[Ed[i].end] > size[son[dir]])
 63                 son[dir] = Ed[i].end;
 64         }
 65 }
 66 
 67 void dfs2(ll dir , ll t){
 68     top[dir] = t;
 69     ind[dir] = ++ts;
 70     rk[ts] = dir;
 71     if(!son[dir])
 72         return;
 73     dfs2(son[dir] , t);
 74     for(ll i = head[dir] ; i ; i = Ed[i].upEd)    
 75         if(Ed[i].end != son[dir] && Ed[i].end != fa[dir])
 76             dfs2(Ed[i].end , Ed[i].end);
 77 }
 78 
 79 inline void pushup(ll dir){
 80     SegTree[dir].sum = SegTree[dir << 1].sum + SegTree[dir << 1 | 1].sum;
 81 }
 82 
 83 inline void pushdown(ll dir){
 84     if(SegTree[dir].mark){
 85         SegTree[dir << 1].sum += SegTree[dir].mark * (SegTree[dir << 1].r - SegTree[dir << 1].l + 1);
 86         SegTree[dir << 1 | 1].sum += SegTree[dir].mark * (SegTree[dir << 1 | 1].r - SegTree[dir << 1 | 1].l + 1);
 87         SegTree[dir << 1].mark += SegTree[dir].mark;
 88         SegTree[dir << 1 | 1].mark += SegTree[dir].mark;
 89         SegTree[dir].mark = 0;
 90     }
 91 }
 92 
 93 void init(ll dir , ll l , ll r){
 94     SegTree[dir].l = l;
 95     SegTree[dir].r = r;
 96     if(l == r)
 97         SegTree[dir].sum = val[rk[l]];
 98     else{
 99         init(dir << 1 , l , l + r >> 1);
100         init(dir << 1 | 1 , (l + r >> 1) + 1 , r);
101         pushup(dir);
102     }
103 }
104 
105 void change(ll dir , ll l , ll r , ll mark){
106     if(SegTree[dir].l >= l && SegTree[dir].r <= r){
107         SegTree[dir].sum += mark * (SegTree[dir].r - SegTree[dir].l + 1);
108         SegTree[dir].mark += mark;
109         return;
110     }
111     pushdown(dir);
112     if(l <= SegTree[dir].l + SegTree[dir].r >> 1)
113         change(dir << 1 , l , r , mark);
114     if(r > SegTree[dir].l + SegTree[dir].r >> 1)
115         change(dir << 1 | 1 , l , r , mark);
116     pushup(dir);
117 }
118 
119 ll query(ll dir , ll l , ll r){
120     if(SegTree[dir].l >= l && SegTree[dir].r <= r)
121         return SegTree[dir].sum;
122     pushdown(dir);
123     ll sum = 0;
124     if(l <= SegTree[dir].l + SegTree[dir].r >> 1)
125         sum += query(dir << 1 , l , r);
126     if(r > SegTree[dir].l + SegTree[dir].r >> 1)
127         sum += query(dir << 1 | 1 , l , r);
128     return sum;
129 }
130 
131 inline void work1(ll x , ll y){
132     change(1 , ind[x] , ind[x] , y);
133 }
134 
135 inline void work2(ll x , ll y){
136     change(1 , ind[x] , ind[x] + size[x] - 1 , y);
137 }
138 
139 inline void work3(ll x){
140     ll sum = 0;
141     while(top[x] - 1){
142         sum += query(1 , ind[top[x]] , ind[x]);
143         x = fa[top[x]];
144     }
145     prll(sum + query(1 , 1 , ind[x]));
146 }
147 
148 int main(){
149     N = read();
150     ll K = read();
151     for(ll i = 1 ; i <= N ; i++)
152         val[i] = read();
153     for(ll i = 1 ; i < N ; i++){
154         ll a = read() , b = read();
155         addEd(a , b);
156         addEd(b , a);
157     }
158     dfs1(1 , 1 , 0);
159     dfs2(1 , 1);
160     init(1 , 1 , N);
161     while(K--){
162         ll a = read() , b = read() , c;
163         switch(a){
164             case 1:
165                 c = read();
166                 work1(b , c);
167                 break;
168             case 2:
169                 c = read();
170                 work2(b , c);
171                 break;
172             case 3:
173                 work3(b);
174         }
175     }
176     return 0;
177 }
树上操作

SHOI2012 魔法树

  1 #include<bits/stdc++.h>
  2 #define MAXN 100010
  3 #define ll long long
  4 using namespace std;
  5 
  6 inline ll read() {
  7     ll a = 0;
  8     bool f = 0;
  9     char c = getchar();
 10     while(!isdigit(c)) {
 11         if(c == '-')
 12             f = 1;
 13         c = getchar();
 14     }
 15     while(isdigit(c)) {
 16         a = (a << 3) + (a << 1) + (c ^ '0');
 17         c = getchar();
 18     }
 19     return f ? -a : a;
 20 }
 21 
 22 int output[20];
 23 inline void print(ll x) {
 24     if(x == 0)
 25         putchar('0');
 26     else {
 27         if(x < 0) {
 28             putchar('-');
 29             x = -x;
 30         }
 31         int dirN = 0;
 32         while(x) {
 33             output[dirN++] = x % 10;
 34             x /= 10;
 35         }
 36         while(dirN)
 37             putchar(output[--dirN] + 48);
 38     }
 39     putchar('\n');
 40 }
 41 
 42 struct node{
 43     ll l , r , sum , add;
 44 }Tree[MAXN << 2];
 45 struct Edge{
 46     ll end , upEd;
 47 }Ed[MAXN];
 48 ll fa[MAXN] , top[MAXN] , dep[MAXN] = {0 , 1} , val[MAXN] , size[MAXN] , ch[MAXN] , head[MAXN] , ind[MAXN] , rk[MAXN];
 49 ll N , cntEd , ts;
 50 
 51 inline void addEd(ll a , ll b){
 52     Ed[++cntEd].end = b;
 53     Ed[cntEd].upEd = head[a];
 54     head[a] = cntEd;
 55 }
 56 
 57 void dfs1(ll now){
 58     size[now] = 1;
 59     for(ll i = head[now] ; i ; i = Ed[i].upEd)
 60         if(Ed[i].end != fa[now]){
 61             fa[Ed[i].end] = now;
 62             dep[Ed[i].end] = dep[now] + 1;
 63             dfs1(Ed[i].end);
 64             size[now] += size[Ed[i].end];
 65             if(size[Ed[i].end] > size[ch[now]])
 66                 ch[now] = Ed[i].end;
 67         }
 68 }
 69 
 70 void dfs2(ll now , ll t){
 71     top[now] = t;
 72     ind[now] = ++ts;
 73     rk[ts] = now;
 74     if(!ch[now])
 75         return;
 76     dfs2(ch[now] , t);
 77     for(ll i = head[now] ; i ; i = Ed[i].upEd)
 78         if(Ed[i].end != fa[now] && Ed[i].end != ch[now])
 79             dfs2(Ed[i].end , Ed[i].end);
 80 }
 81 
 82 inline void pushup(ll dir){
 83     Tree[dir].sum = Tree[dir << 1].sum + Tree[dir << 1 | 1].sum;
 84 }
 85 
 86 inline void pushdown(ll dir){
 87     if(Tree[dir].add){
 88         Tree[dir << 1].add += Tree[dir].add;
 89         Tree[dir << 1 | 1].add += Tree[dir].add;
 90         Tree[dir << 1].sum += (Tree[dir << 1].r - Tree[dir << 1].l + 1) * Tree[dir].add;
 91         Tree[dir << 1 | 1].sum += (Tree[dir << 1 | 1].r - Tree[dir << 1 | 1].l + 1) * Tree[dir].add;
 92         Tree[dir].add = 0;
 93     }
 94 }
 95 
 96 void init(ll dir , ll l , ll r){
 97     Tree[dir].l = l;
 98     Tree[dir].r = r;
 99     if(l == r){
100         Tree[dir].sum = val[rk[l]];
101         return;
102     }
103     init(dir << 1 , l , l + r >> 1);
104     init(dir << 1 | 1 , (l + r >> 1) + 1 , r);
105     pushup(dir);
106 }
107 
108 void add(ll dir , ll l , ll r , ll L , ll R , ll num){
109     if(l >= L && r <= R){
110         Tree[dir].add += num;
111         Tree[dir].sum += (r - l + 1) * num;
112         return;
113     }
114     pushdown(dir);
115     if(l + r >> 1 >= L)
116         add(dir << 1 , l , l + r >> 1 , L , R , num);
117     if(l + r >> 1 < R)
118         add(dir << 1 | 1 , (l + r >> 1) + 1 , r , L , R , num);
119     pushup(dir);
120 }
121 
122 ll getSum(int dir , int l , int r , int L , int R){
123     if(l >= L && r <= R)
124         return Tree[dir].sum;
125     pushdown(dir);
126     ll sum = 0;
127     if(l + r >> 1 >= L)
128         sum += getSum(dir << 1 , l , l + r >> 1 , L , R);
129     if(l + r >> 1 < R)
130         sum += getSum(dir << 1 | 1 , (l + r >> 1) + 1 , r , L , R);
131     return sum;
132 }
133 
134 void change(int u , int v , ll d){
135     int tu = top[u] , tv = top[v];
136     while(tu != tv){
137         if(dep[tu] < dep[tv]){
138             swap(u , v);
139             swap(tu , tv);
140         }
141         add(1 , 1 , N , ind[tu] , ind[u] , d);
142         u = fa[tu];
143         tu = top[u];
144     }
145     if(dep[u] < dep[v])
146         swap(u , v);
147     add(1 , 1 , N , ind[v] , ind[u] , d);
148 }
149 
150 void query(int u){
151     print(getSum(1 , 1 , N , ind[u] , ind[u] + size[u] - 1));
152 }
153 
154 int main(){
155     N = read();
156     for(int i = 2 ; i <= N ; i++){
157         int a = read() + 1 , b = read() + 1;
158         addEd(a , b);
159     }
160     dfs1(1);
161     dfs2(1 , 1);
162     init(1 , 1 , N);
163     for(int T = read() ; T ; T--){
164         char c = getchar();
165         while(c != 'A' && c != 'Q')
166             c = getchar();
167         if(c == 'A'){
168             ll a = read() + 1 , b = read() + 1 , c = read();
169             change(a , b , c);
170         }
171         else
172             query(read() + 1);
173     }
174     return 0;
175 }
魔法树

SDOI2011 染色

  1 #include<bits/stdc++.h>
  2 #define MAXN 100001
  3 using namespace std;
  4 struct node{
  5     int l , r , colNum , lCol , rCol , mark;
  6 }Tree[MAXN << 2];
  7 struct Edge{
  8     int end , upEd;
  9 }Ed[MAXN << 1];
 10 int color[MAXN] , head[MAXN] , size[MAXN] , son[MAXN] , fa[MAXN] , dep[MAXN];
 11 int cntEd , N , M , ts , sum , lCol , rCol , top[MAXN] , rk[MAXN] , ind[MAXN];
 12 
 13 inline void addEd(int a , int b){
 14     Ed[++cntEd].end = b;
 15     Ed[cntEd].upEd = head[a];
 16     head[a] = cntEd;
 17 }
 18 
 19 void dfs1(int dir , int depth , int father){
 20     size[dir] = 1;
 21     fa[dir] = father;
 22     dep[dir] = depth;
 23     for(int i = head[dir] ; i ; i = Ed[i].upEd)
 24         if(Ed[i].end != father){
 25             dfs1(Ed[i].end , depth + 1 , dir);
 26             size[dir] += size[Ed[i].end];
 27             if(size[son[dir]] < size[Ed[i].end])
 28                 son[dir] = Ed[i].end;
 29         }
 30 }
 31 
 32 void dfs2(int dir , int t){
 33     top[dir] = t;
 34     ind[dir] = ++ts;
 35     rk[ts] = dir;
 36     if(!son[dir])
 37         return;
 38     dfs2(son[dir] , t);
 39     for(int i = head[dir] ; i ; i = Ed[i].upEd)
 40         if(Ed[i].end != son[dir] && Ed[i].end != fa[dir])
 41             dfs2(Ed[i].end , Ed[i].end);
 42 }
 43 
 44 inline void pushup(int dir){
 45     Tree[dir].colNum = Tree[dir << 1 | 1].colNum + Tree[dir << 1].colNum - (Tree[dir << 1].rCol == Tree[dir << 1 | 1].lCol);
 46     Tree[dir].lCol = Tree[dir << 1].lCol;
 47     Tree[dir].rCol = Tree[dir << 1 | 1].rCol;
 48 }
 49 
 50 inline void pushdown(int dir){
 51     if(Tree[dir].mark){
 52         Tree[dir << 1].lCol = Tree[dir << 1].mark = Tree[dir << 1].rCol = Tree[dir].mark;
 53         Tree[dir << 1 | 1].lCol = Tree[dir << 1 | 1].mark = Tree[dir << 1 | 1].rCol = Tree[dir].mark;
 54         Tree[dir << 1].colNum = Tree[dir << 1 | 1].colNum = 1;
 55         Tree[dir].mark = 0;
 56     }
 57 }
 58 
 59 void init(int dir , int l , int r){
 60     Tree[dir].l = l;
 61     Tree[dir].r = r;
 62     if(l == r){
 63         Tree[dir].lCol = Tree[dir].rCol = color[rk[l]];
 64         Tree[dir].colNum = 1;
 65     }
 66     else{
 67         init(dir << 1 , l , l + r >> 1);
 68         init(dir << 1 | 1 , (l + r >> 1) + 1 , r);
 69         pushup(dir);
 70     }
 71 }
 72 
 73 void change(int dir , int l , int r , int col){
 74     if(Tree[dir].l >= l && Tree[dir].r <= r){
 75         Tree[dir].lCol = Tree[dir].rCol = Tree[dir].mark = col;
 76         Tree[dir].colNum = 1;
 77         return;
 78     }
 79     pushdown(dir);
 80     if(Tree[dir].l + Tree[dir].r >> 1 >= l)
 81         change(dir << 1 , l , r , col);
 82     if(Tree[dir].l + Tree[dir].r >> 1 < r)
 83         change(dir << 1 | 1 , l , r , col);
 84     pushup(dir);
 85 }
 86 
 87 void findRight(int dir , int l , int r){
 88     if(Tree[dir].l >= l && Tree[dir].r <= r){
 89         sum += Tree[dir].colNum - (Tree[dir].rCol == rCol);
 90         rCol = Tree[dir].lCol;
 91         return;
 92     }
 93     pushdown(dir);
 94     if(Tree[dir].l + Tree[dir].r >> 1 < r)
 95         findRight(dir << 1 | 1 , l , r);
 96     if(Tree[dir].l + Tree[dir].r >> 1 >= l)
 97         findRight(dir << 1 , l , r);
 98 }
 99 
100 void findLeft(int dir, int l , int r){
101     if(Tree[dir].l >= l && Tree[dir].r <= r){
102         sum += Tree[dir].colNum - (Tree[dir].rCol == lCol);
103         lCol = Tree[dir].lCol;
104         return;
105     }
106     pushdown(dir);
107     if(Tree[dir].l + Tree[dir].r >> 1 < r)
108         findLeft(dir << 1 | 1 , l , r);
109     if(Tree[dir].l + Tree[dir].r >> 1 >= l)
110         findLeft(dir << 1 , l , r);
111 }
112 
113 inline void work1(int x , int y , int col){
114     int fx = top[x] , fy = top[y];
115     while(fx != fy)
116         if(dep[fx] >= dep[fy]){
117             change(1 , ind[fx] , ind[x] , col);
118             x = fa[fx];
119             fx = top[x];
120         }
121         else{
122             change(1 , ind[fy] , ind[y] , col);
123             y = fa[fy];
124             fy = top[y];
125         }
126     if(ind[x] <= ind[y])
127         change(1 , ind[x] , ind[y] , col);
128     else
129         change(1 , ind[y] , ind[x] , col);
130 }
131 
132 inline int work2(int x , int y){
133     int fx = top[x] , fy = top[y];
134     sum = lCol = rCol = 0;
135     while(fx != fy){
136         if(dep[fx] >= dep[fy]){
137             findLeft(1 , ind[fx] , ind[x]);
138             x = fa[fx];
139             fx = top[x];
140         }
141         else{
142             findRight(1 , ind[fy] , ind[y]);
143             y = fa[fy];
144             fy = top[y];
145         }
146     }
147     if(ind[x] < ind[y])
148         findRight(1 , ind[x] , ind[y]);
149     else
150         findLeft(1 , ind[y] , ind[x]);
151     sum -= (lCol == rCol);
152     return sum;
153 }
154 
155 int main(){
156     cin >> N >> M;
157     for(int i = 1 ; i <= N ; i++)
158         cin >> color[i];
159     for(int i = 1 ; i < N ; i++){
160         int a , b;
161         cin >> a >> b;
162         addEd(a , b);
163         addEd(b , a);
164     }
165     dfs1(1 , 1 , 0);
166     dfs2(1 , 1);
167     init(1 , 1 , N);
168     while(M--){
169         char c;
170         int a , b;
171         cin >> c >> a >> b;
172         if(c == 'Q')
173             cout << work2(a , b) << endl;
174         else{
175             int d;
176             cin >> d;
177             work1(a , b , d);
178         }
179     }
180     return 0;
181 }
染色

NOI2015 软件包管理器

  1 #include<bits/stdc++.h>
  2 #define MAXN 100002
  3 using namespace std;
  4 
  5 struct node{
  6     int l , r , sum1 , mark;
  7 }Tree[MAXN << 2];
  8 int head[MAXN] , upEd[MAXN] , size[MAXN] , fa[MAXN] , son[MAXN] , dep[MAXN];
  9 int N , Q , ts , top[MAXN] , ind[MAXN];
 10 
 11 void dfs1(int dir , int father){
 12     size[dir] = 1;
 13     dep[dir] = dep[fa[dir] = father] + 1;
 14     for(int i = head[dir] ; i ; i = upEd[i]){
 15         dfs1(i , dir);
 16         size[dir] += size[i];
 17         if(size[son[dir]] < size[i])
 18             son[dir] = i;
 19     }
 20 }
 21 
 22 void dfs2(int dir , int t){
 23     top[dir] = t;
 24     ind[dir] = ++ts;
 25     if(!son[dir])
 26         return;
 27     dfs2(son[dir] , t);
 28     for(int i = head[dir] ; i ; i = upEd[i])
 29         if(son[dir] != i)
 30             dfs2(i , i);
 31 }
 32 
 33 inline void pushup(int dir){
 34     Tree[dir].sum1 = Tree[dir << 1].sum1 + Tree[dir << 1 | 1].sum1;
 35 }
 36 
 37 inline void pushdown(int dir){
 38     if(Tree[dir].mark + 1){
 39         Tree[dir << 1].mark = Tree[dir << 1 | 1].mark = Tree[dir].mark;
 40         Tree[dir << 1].sum1 = (Tree[dir << 1].r - Tree[dir << 1].l + 1) * Tree[dir].mark;
 41         Tree[dir << 1 | 1].sum1 = (Tree[dir << 1 | 1].r - Tree[dir << 1 | 1].l + 1) * Tree[dir].mark;
 42         Tree[dir].mark = -1;
 43     }
 44 }
 45 
 46 void init(int l , int r , int dir){
 47     Tree[dir].l = l;
 48     Tree[dir].r = r;
 49     Tree[dir].mark = -1;
 50     if(l != r){
 51         init(l , l + r >> 1 , dir << 1);
 52         init((l + r >> 1) + 1 , r , dir << 1 | 1);
 53     }
 54 }
 55 
 56 void change(int l , int r , int dir , int mark){
 57     if(Tree[dir].l >= l && Tree[dir].r <= r){
 58         Tree[dir].sum1 = (Tree[dir].r - Tree[dir].l + 1) * (Tree[dir].mark = mark);
 59         return;
 60     }
 61     pushdown(dir);
 62     if(l <= Tree[dir].l + Tree[dir].r >> 1)
 63         change(l , r , dir << 1 , mark);
 64     if(Tree[dir].l + Tree[dir].r >> 1 < r)
 65         change(l , r , dir << 1 | 1 , mark);
 66     pushup(dir);
 67 }
 68 
 69 int getSum(int l , int r , int dir){
 70     if(Tree[dir].l >= l && Tree[dir].r <= r)
 71         return Tree[dir].sum1;
 72     pushdown(dir);
 73     int sum = 0;
 74     if(l <= Tree[dir].l + Tree[dir].r >> 1)
 75         sum += getSum(l , r , dir << 1);
 76     if(Tree[dir].l + Tree[dir].r >> 1 < r)
 77         sum += getSum(l , r , dir << 1 | 1);
 78     return sum;
 79 }
 80 
 81 inline int work1(int dir){
 82     if(getSum(ind[dir] , ind[dir] , 1))
 83         return 0;
 84     int sum = 0;
 85     while(top[dir] - 1){
 86         sum += ind[dir] - ind[top[dir]] + 1 - getSum(ind[top[dir]] , ind[dir] , 1);
 87         change(ind[top[dir]] , ind[dir] , 1 , 1);
 88         dir = fa[top[dir]];
 89     }
 90     sum += ind[dir] - getSum(1 , ind[dir] , 1);
 91     change(1 , ind[dir] , 1 , 1);
 92     return sum;
 93 }
 94 
 95 inline int work2(int dir){
 96     if(!getSum(ind[dir] , ind[dir] , 1))
 97         return 0;
 98     int sum = getSum(ind[dir] , ind[dir] + size[dir] - 1 , 1);
 99     change(ind[dir] , ind[dir] + size[dir] - 1 , 1 , 0);
100     return sum;
101 }
102 
103 int main(){
104     cin >> N;
105     for(int i = 2 ; i <= N ; i++){
106         int a;
107         cin >> a;
108         upEd[i] = head[a + 1];
109         head[a + 1] = i;
110     }
111     dfs1(1 , 0);
112     dfs2(1 , 1);
113     init(1 , N , 1);
114     string s;
115     for(cin >> Q ; Q ; Q--){
116         int a;
117         cin >> s >> a;
118         a++;
119         if(s[0] == 'i')
120             cout << work1(a) << endl;
121         else
122             cout << work2(a) << endl;
123     }
124     return 0;
125 }
软件包管理器

月下“毛景树”

  1 #include<bits/stdc++.h>
  2 #define MAXN 100001
  3 using namespace std;
  4 
  5 inline int read(){
  6     int a = 0;
  7     bool f = 0;
  8     char c = getchar();
  9     while(!isdigit(c)){
 10         if(c == '-')
 11             f = 1;
 12         c = getchar();
 13     }
 14     while(isdigit(c)){
 15         a = (a << 3) + (a << 1) + (c ^ '0');
 16         c = getchar();
 17     }
 18     return f ? -a : a;
 19 }
 20 char output[12];
 21 inline void print(int x){
 22     int dirN = 11;
 23     if(x == 0)
 24         fwrite("0" , sizeof(char) , 1 , stdout);
 25     else{
 26         if(x < 0){
 27             x = -x;
 28             fwrite("-" , sizeof(char) , 1 , stdout);
 29         }
 30         while(x){
 31                output[--dirN] = x % 10 + 48;
 32             x /= 10;
 33         }
 34         fwrite(output + dirN , 1 , strlen(output + dirN) , stdout);
 35     }
 36     fwrite("\n" , 1 , 1 , stdout);
 37 }
 38 
 39 struct node{
 40     int l , r , markAll , markAdd , maxN;
 41 }Tree[MAXN << 2];
 42 struct Edge{
 43     int end , w , upEd;
 44 }Ed[MAXN << 1];
 45 int val[MAXN] , head[MAXN] , size[MAXN] , fa[MAXN] , son[MAXN] , dep[MAXN];
 46 int rk[MAXN] , ind[MAXN] , top[MAXN] , N , ts , cntEd;
 47 
 48 inline int max(int a , int b){
 49     return a > b ? a : b;
 50 }
 51 
 52 inline void addEd(int a , int b , int c){
 53     Ed[++cntEd].end = b;
 54     Ed[cntEd].upEd = head[a];
 55     Ed[cntEd].w = c;
 56     head[a] = cntEd;
 57 }
 58 
 59 void dfs1(int dir , int father){
 60     size[dir] = 1;
 61     dep[dir] = dep[fa[dir] = father] + 1;
 62     for(int i = head[dir] ; i ; i = Ed[i].upEd)
 63         if(!dep[Ed[i].end]){
 64             val[Ed[i].end] = Ed[i].w;
 65             dfs1(Ed[i].end , dir);
 66             size[dir] += size[Ed[i].end];
 67             if(size[son[dir]] < size[Ed[i].end])
 68                 son[dir] = Ed[i].end;
 69         }
 70 }
 71 
 72 void dfs2(int dir , int t){
 73     top[dir] = t;
 74     rk[ind[dir] = ++ts] = dir;
 75     if(!son[dir])
 76         return;
 77     dfs2(son[dir] , t);
 78     for(int i = head[dir] ; i ; i = Ed[i].upEd)
 79         if(Ed[i].end != son[dir] && Ed[i].end != fa[dir])
 80             dfs2(Ed[i].end , Ed[i].end);
 81 }
 82 
 83 inline void pushup(int dir){
 84     Tree[dir].maxN = max(Tree[dir << 1].maxN , Tree[dir << 1 | 1].maxN);
 85 }
 86 
 87 inline void pushdown(int dir){
 88     if(Tree[dir].markAll + 1){
 89         Tree[dir << 1].markAll = Tree[dir << 1 | 1].markAll = Tree[dir << 1].maxN = Tree[dir << 1 | 1].maxN = Tree[dir].markAll;
 90         Tree[dir << 1].markAdd = Tree[dir << 1 | 1].markAdd = 0;
 91         Tree[dir].markAll = -1;
 92     }
 93     if(Tree[dir].markAdd){
 94         Tree[dir << 1].maxN += Tree[dir].markAdd;
 95         Tree[dir << 1].markAdd += Tree[dir].markAdd;
 96         Tree[dir << 1 | 1].maxN += Tree[dir].markAdd;
 97         Tree[dir << 1 | 1].markAdd += Tree[dir].markAdd;
 98         Tree[dir].markAdd = 0;
 99     }
100 }
101 
102 void init(int dir , int l , int r){
103     Tree[dir].l = l;
104     Tree[dir].r = r;
105     Tree[dir].markAll = -1;
106     if(l == r)
107         Tree[dir].maxN = val[rk[l]];
108     else{
109         init(dir << 1 , l , (l + r) >> 1);
110         init(dir << 1 | 1 , ((l + r) >> 1) + 1 , r);
111         pushup(dir);
112     }
113 }
114 
115 void changeAll(int dir , int l , int r , int val){
116     if(Tree[dir].l >= l && Tree[dir].r <= r){
117         Tree[dir].markAll = Tree[dir].maxN = val;
118         Tree[dir].markAdd = 0;
119         return;
120     }
121     pushdown(dir);
122     if(l <= (Tree[dir].l + Tree[dir].r) >> 1)
123         changeAll(dir << 1 , l , r , val);
124     if(r > (Tree[dir].l + Tree[dir].r) >> 1)
125         changeAll(dir << 1 | 1 , l , r , val);
126     pushup(dir);
127 }
128 
129 void changeAdd(int dir , int l , int r , int val){
130     if(Tree[dir].l >= l && Tree[dir].r <= r){
131         Tree[dir].maxN += val;
132         Tree[dir].markAdd += val;
133         return;
134     }
135     pushdown(dir);
136     if(l <= (Tree[dir].l + Tree[dir].r) >> 1)
137         changeAdd(dir << 1 , l , r , val);
138     if(r > (Tree[dir].l + Tree[dir].r) >> 1)
139         changeAdd(dir << 1 | 1 , l , r , val);
140     pushup(dir);
141 }
142 
143 int findMax(int dir , int l , int r){
144     if(Tree[dir].l >= l && Tree[dir].r <= r)
145         return Tree[dir].maxN;
146     pushdown(dir);
147     int maxN = 0;
148     if(l <= (Tree[dir].l + Tree[dir].r) >> 1)
149         maxN = max(maxN , findMax(dir << 1 , l , r));
150     if(r > (Tree[dir].l + Tree[dir].r) >> 1)
151         maxN = max(maxN , findMax(dir << 1 | 1 , l , r));
152     return maxN;
153 }
154 
155 inline int cmp(int a , int b){
156     return dep[a] > dep[b] ? ind[a] : ind[b];
157 }
158 
159 inline void work1(int l , int r , int val){
160     int tl = top[l] , tr = top[r];
161     while(tl != tr)
162         if(dep[tl] >= dep[tr]){
163             changeAll(1 , ind[tl] , ind[l] , val);
164             tl = top[l = fa[tl]];
165         }
166         else{
167             changeAll(1 , ind[tr] , ind[r] , val);
168             tr = top[r = fa[tr]];
169         }
170     if(ind[l] < ind[r])
171         changeAll(1 , ind[l] + 1 , ind[r] , val);
172     if(ind[r] < ind[l])
173         changeAll(1 , ind[r] + 1 , ind[l] , val);
174 }
175 
176 inline void work2(int l , int r , int val){
177     int tl = top[l] , tr = top[r];
178     while(tl != tr)
179         if(dep[tl] >= dep[tr]){
180             changeAdd(1 , ind[tl] , ind[l] , val);
181             tl = top[l = fa[tl]];
182         }
183         else{
184             changeAdd(1 , ind[tr] , ind[r] , val);
185             tr = top[r = fa[tr]];
186         }
187     if(ind[l] < ind[r])
188         changeAdd(1 , ind[l] + 1 , ind[r] , val);
189     if(ind[r] < ind[l])
190         changeAdd(1 , ind[r] + 1 , ind[l] , val);
191 }
192 
193 inline void work3(int l , int r){
194     int tl = top[l] , tr = top[r] , maxN = 0;
195     while(tl != tr)
196         if(dep[tl] >= dep[tr]){
197             maxN = max(maxN , findMax(1 , ind[tl] , ind[l]));
198             tl = top[l = fa[tl]];
199         }
200         else{
201             maxN = max(maxN , findMax(1 , ind[tr] , ind[r]));
202             tr = top[r = fa[tr]];
203         }
204     if(ind[l] < ind[r])
205         maxN = max(maxN , findMax(1 , ind[l] + 1 , ind[r]));
206     if(ind[r] < ind[l])
207         maxN = max(maxN , findMax(1 , ind[r] + 1 , ind[l]));
208     print(maxN);
209 }
210 
211 int main(){
212     N = read();
213     for(int i = 1 ; i < N ; i++){
214         int a = read() , b = read() , c = read();
215         addEd(a , b , c);
216         addEd(b , a , c);
217     }
218     dfs1(1 , 0);
219     dfs2(1 , 1);
220     init(1 , 1 , N);
221     string s;
222     while(cin >> s && s[1] != 't'){
223         int a = read() , b = read() , c;
224         switch(s[1]){
225             case 'h':
226                 changeAll(1 , cmp(Ed[a << 1].end , Ed[(a << 1) - 1].end) , cmp(Ed[a << 1].end , Ed[(a << 1) - 1].end) , b);
227                 break;
228             case 'o':
229                 c = read();
230                 work1(a , b , c);
231                 break;
232             case 'd':
233                 c = read();
234                 work2(a , b , c);
235                 break;
236             default:
237                 work3(a , b);
238         }
239     }
240     return 0;
241 }
月下毛景树

b.较难

PS:其实树链剖分比较难的还是在线段树上

NOIP2018D2T3的动态DP模板

Ynoi2017 由乃的OJ Sol

当然,不要忘记了SPOJ的Qtree和Can you answer these queries系列的题目!

转载于:https://www.cnblogs.com/Itst/p/10013373.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值