树链剖分是一个比较好理解的数据结构,码量不是很大(如果你发现你写的很多,那么一定是线段树的锅)
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.基础
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 }
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 }
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 }
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 }
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:其实树链剖分比较难的还是在线段树上
当然,不要忘记了SPOJ的Qtree和Can you answer these queries系列的题目!