[模板]洛谷T3384 树链剖分

树剖是干什么的?

考虑这样的情况:有一棵树,现在要对其进行路径(两节点间)操作、子树操作,例如将路径上(子树上)的所有节点全部加上一个值、求和等等。

直接暴力操作固然是可行的,但时间肯定是个问题。

这时我们想,如果能用数据结构维护树上节点就好了,但是树的“张牙舞爪”的样子,使得这个操作难以完成。

于是,树剖应运而生。树剖的作用是,把树拆分成若干条“链”,显然,“链”是线性的,方便用数据结构维护。

具体的拆分方式名为“轻重链剖分”。使用这种拆分方式,可以使任一节点到根的路径上,经过的重链和轻边数量均不超过logn,这里的n指的是树的节点总数。关于具体概念及复杂度证明请自行百度,此处不再赘述。

树剖过程需要求得的一系列数组如下:

fa[]:节点的父亲节点(根节点为无);

dep[]:节点深度;

size[]:以节点为根的子树的节点总数;

son[]:节点的重儿子编号;

top[]:节点所处重链的顶端节点;

dfsx[]:按照重链优先遍历出的DFS序;

pos[]:节点在数据结构中的位置。

初始化过程:

1.存图;

2.进行第一遍DFS,自根向下遍历(这个过程类似于无根树转有根树),求出fa[]、dep[]、size[]、son[];

3.进行第二遍DFS,按照重链优先的顺序遍历,求出top[]、dfsx[],这时的DFS序满足:同一条重链或同一棵子树上的节点在DFS序中是连续的;

4.根据DFS序计算pos[],细节请见代码,我把这个过程叫做“反向映射”;

5.按照DFS序,将节点值存入数据结构(我用的是线段树)。

查询及修改:

1.路径操作,需要知道两节点的LCA,但是不必单独去求,只需按照重链和轻边向上跳即可到达LCA(轻边跳一下,重链跳到top的父节点,话说我也不明白这样搞为什么是对的),沿路修改/查询即可,复杂度log^2n,细节请见代码。

2.子树操作,因为同一棵子树上的节点在数据结构中是连续的,所以借助size值,仅修改/查询一次即可,复杂度logn。

最后提醒一句,适当取模,取少了计算结果会溢出,取多了会TLE。。。

代码如下:

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cstring>
  4 #include<cmath>
  5 #include<ctime>
  6 #include<cstdlib>
  7 
  8 #include<string>
  9 #include<stack>
 10 #include<queue>
 11 #include<vector>
 12 #include<algorithm>
 13 #include<map>
 14 #include<set>
 15 
 16 #define ll long long
 17 
 18 using namespace std;
 19 
 20 inline void readint(int &x){
 21     x=0;
 22     char t=getchar();
 23     bool f=0;
 24     
 25     while(t<'0' || t>'9'){
 26         if(t=='-')f=1;
 27         t=getchar();
 28     }
 29     
 30     while(t>='0' && t<='9'){
 31         x=(x<<3)+(x<<1)+t-'0';
 32         t=getchar();
 33     }
 34     
 35     if(f)x=-x;
 36 }
 37 
 38 inline void readll(ll &x){
 39     x=0;
 40     char t=getchar();
 41     bool f=0;
 42     
 43     while(t<'0' || t>'9'){
 44         if(t=='-')f=1;
 45         t=getchar();
 46     }
 47     
 48     while(t>='0' && t<='9'){
 49         x=(x<<3)+(x<<1)+t-'0';
 50         t=getchar();
 51     }
 52     
 53     if(f)x=-x;
 54 }
 55 
 56 ll a[200010];  //点值 
 57 
 58 int v[200010];
 59 int first[200010];   
 60 int next[200010];
 61 int ord=0;  //邻接表 
 62 
 63 int fa[200010];
 64 int dep[200010];
 65 int size[200010];
 66 int son[200010];
 67 
 68 int top[200010];
 69 int dfsx[200010];
 70 int xu=0;
 71 
 72 int pos[200010];
 73 
 74 int n,m,root,mod,i;
 75 int f,x,y;
 76 ll k;
 77 
 78 inline void setup(){
 79     memset(first,0,sizeof(first));
 80     memset(next,0,sizeof(next));
 81     
 82     memset(son,0,sizeof(son));
 83 }
 84 
 85 inline void addedge(){
 86     ord++;
 87     v[ord]=y;
 88     next[ord]=first[x];
 89     first[x]=ord;
 90     
 91     ord++;
 92     v[ord]=x;
 93     next[ord]=first[y];
 94     first[y]=ord;
 95 }
 96 
 97 void dfs1(int);
 98 void dfs2(int);
 99 
100 inline void path_update(int,int);
101 inline ll path_query(int,int);
102 inline void son_update(int);
103 inline ll son_query(int);
104 
105 struct sgt{
106     ll sum[800010];
107     ll addv[800010];
108     
109     void build(int o,int l,int r){
110         addv[o]=0;
111         
112         if(l==r)sum[o]=a[dfsx[l]];
113         else{
114             int mid=(l+r)>>1;
115             int lson=o<<1;
116             int rson=lson|1;
117             
118             build(lson,l,mid);
119             build(rson,mid+1,r);
120             
121             sum[o]=(sum[lson]+sum[rson])%mod;
122         }
123     }
124     
125     void pushdown(int o,int l,int r,int mid,int lson,int rson){
126         addv[lson]=(addv[lson]+addv[o])%mod;
127         addv[rson]=(addv[rson]+addv[o])%mod;
128         
129         sum[lson]=(sum[lson]+addv[o]*(mid-l+1))%mod;
130         sum[rson]=(sum[rson]+addv[o]*(r-mid))%mod;
131         
132         addv[o]=0;
133     }
134     
135     void update(int o,int l,int r,int a,int b,int x){
136         if(l>=a && r<=b){
137             addv[o]=(addv[o]+x)%mod;
138             sum[o]=(sum[o]+x*(r-l+1))%mod;
139             return;
140         }
141         else{
142             int mid=(l+r)>>1;
143             int lson=o<<1;
144             int rson=lson|1;
145             
146             if(addv[o])pushdown(o,l,r,mid,lson,rson);
147             
148             if(a<=mid)update(lson,l,mid,a,b,x);
149             if(b>mid)update(rson,mid+1,r,a,b,x);
150             
151             sum[o]=(sum[lson]+sum[rson])%mod;
152         }
153     }
154     
155     ll query(int o,int l,int r,int a,int b){
156         if(l>=a && r<=b)return sum[o];
157         else{
158             int mid=(l+r)>>1;
159             int lson=o<<1;
160             int rson=lson|1;
161             ll ans=0;
162             
163             if(addv[o])pushdown(o,l,r,mid,lson,rson);
164             
165             if(a<=mid)ans+=query(lson,l,mid,a,b);
166             if(b>mid)ans=(ans+query(rson,mid+1,r,a,b))%mod;
167             
168             return ans;
169         }
170     }
171 } tree;
172 
173 int main(){
174     setup();
175     
176     readint(n);readint(m);readint(root);readint(mod);
177     
178     for(register int i=1;i<=n;i++)readll(a[i]);
179     
180     for(register int i=1;i<n;i++){
181         readint(x);readint(y);
182         addedge();
183     }
184     
185     fa[root]=0;
186     dep[root]=1;
187     dfs1(root);
188     
189     top[root]=root;
190     dfs2(root);
191     
192     for(register int i=1;i<=n;i++)pos[dfsx[i]]=i;
193     
194     tree.build(1,1,n);
195     
196     while(m--){
197         readint(f);
198         
199         switch(f){
200             case 1:{
201                 readint(x);readint(y);readll(k);
202                 path_update(x,y);
203                 break;
204             }
205             case 2:{
206                 readint(x);readint(y);
207                 printf("%lld\n",path_query(x,y));
208                 break;
209             }
210             case 3:{
211                 readint(x);readll(k);
212                 son_update(x);
213                 break;
214             }
215             case 4:{
216                 readint(x);
217                 printf("%lld\n",son_query(x));
218                 break;
219             }
220         }
221     }
222     
223     return 0;
224 }
225 
226 void dfs1(int x){  //fa,dep在上层处理 
227     size[x]=1;
228     int e=first[x],u=v[e],maxson=0;
229     
230     while(e){
231         if(u==fa[x]){
232             e=next[e];
233             u=v[e];
234             continue;
235         }
236         
237         fa[u]=x;
238         dep[u]=dep[x]+1;
239         
240         dfs1(u);
241         
242         size[x]+=size[u];
243         if(size[u]>maxson){
244             maxson=size[u];
245             son[x]=u;
246         }
247         
248         e=next[e];
249         u=v[e];
250     }
251 }
252 
253 void dfs2(int x){  //top在上层处理 
254     xu++;
255     dfsx[xu]=x;
256     
257     if(son[x]){
258         top[son[x]]=top[x];
259         dfs2(son[x]);
260     }
261     
262     int e=first[x],u=v[e];
263     
264     while(e){
265         if(u==fa[x] || u==son[x]){
266             e=next[e];
267             u=v[e];
268             continue;
269         }
270         
271         top[u]=u;
272         dfs2(u);
273         
274         e=next[e];
275         u=v[e];
276     }
277 }
278 
279 inline void path_update(int x,int y){
280     int tx=top[x],ty=top[y];
281     
282     while(tx!=ty){
283         if(dep[tx]>dep[ty]){
284             tree.update(1,1,n,pos[tx],pos[x],k);
285             x=fa[tx];
286             tx=top[x];
287         }
288         else{
289             tree.update(1,1,n,pos[ty],pos[y],k);
290             y=fa[ty];
291             ty=top[y];
292         }
293     }
294     
295     if(pos[x]<pos[y])tree.update(1,1,n,pos[x],pos[y],k);
296     else tree.update(1,1,n,pos[y],pos[x],k);
297 }
298 
299 inline ll path_query(int x,int y){
300     ll ans=0;
301     int tx=top[x],ty=top[y];
302     
303     while(tx!=ty){
304         if(dep[tx]>dep[ty]){
305             ans+=tree.query(1,1,n,pos[tx],pos[x]);
306             x=fa[tx];
307             tx=top[x];
308         }
309         else{
310             ans+=tree.query(1,1,n,pos[ty],pos[y]);
311             y=fa[ty];
312             ty=top[y];
313         }
314     }
315     
316     if(pos[x]<pos[y])ans+=tree.query(1,1,n,pos[x],pos[y]);
317     else ans+=tree.query(1,1,n,pos[y],pos[x]);
318     
319     return ans%mod;
320 }
321 
322 inline void son_update(int root){
323     tree.update(1,1,n,pos[root],pos[root]+size[root]-1,k);
324 }
325 
326 inline ll son_query(int root){
327     return tree.query(1,1,n,pos[root],pos[root]+size[root]-1);
328 }
posted @ 2017-10-01 21:40  Running-Coder  阅读(187)  评论(0编辑  收藏  举报