树链剖分模版

Posted white_hat_hacker

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树链剖分模版相关的知识,希望对你有一定的参考价值。

注意事项:

1、把握好“树节点”与“RMQ节点”的关系,

即build时,dat[k]=a[pre[L]];query时,调用需加上tree[x],tree[y]

有时候又不需要加tree[x],比如处理子树。

2、线段树确保正确,数组开4倍

3、树链剖分的循环中,必须先处理链顶深度较大的,如果直接处理节点深度大的,可能出现这种情况:

如图,如果是按照dep[x]>dep[y],那么x直接上去,求的就不是最短路径了

反之,如果按照dep[f2]>dep[f1],则没有问题


  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<algorithm>
  4 #include<cstring>
  5 #define MAXN 100005
  6 #define ll long long
  7 using namespace std;
  8 int first[MAXN],Next[MAXN*2],to[MAXN*2],cnt;
  9 //double edge
 10 ll Val[MAXN];
 11 int dep[MAXN],size[MAXN],fa[MAXN],son[MAXN];
 12 int top[MAXN],tree[MAXN],pre[MAXN],num;
 13 int V,root;
 14 ll MOD;
 15 //tree node -> tree
 16 //pre tree-> node
 17 void Add(int x,int y){
 18     Next[++cnt]=first[x];first[x]=cnt;to[cnt]=y;
 19     Next[++cnt]=first[y];first[y]=cnt;to[cnt]=x;
 20 }
 21 void dfs1(int x){
 22     size[x]=1;
 23     for(int e=first[x];e;e=Next[e]){
 24         int y=to[e];
 25         if(fa[x]==y) continue;
 26         fa[y]=x;
 27         dep[y]=dep[x]+1;
 28         dfs1(y);
 29         size[x]+=size[y];
 30         if(size[y]>size[son[x]]){
 31             son[x]=y;
 32         }
 33     }
 34 }
 35 void dfs2(int x,int t){
 36     top[x]=t;
 37     tree[x]=(++num);
 38     pre[num]=x;
 39     if(!son[x]){
 40         return ;
 41     }
 42     dfs2(son[x],t);
 43     for(int e=first[x];e;e=Next[e]){
 44         int y=to[e];
 45         if(y==fa[x]||y==son[x]) continue;
 46         dfs2(y,y);
 47     }
 48 }
 49 ll dat[MAXN*4];
 50 ll tag[MAXN*4];
 51 //kai si bei
 52 void build(int k,int L,int R){
 53     if(L+1==R){
 54         dat[k]=Val[pre[L]];
 55         return ;
 56         //remember to return here
 57     }
 58     build(k<<1,L,(L+R)>>1);
 59     build(k<<1|1,(L+R)>>1,R);
 60     dat[k]=(dat[k<<1]+dat[k<<1|1])%MOD;
 61 }
 62 void pushdown(int k,int L,int R){
 63     int lc=(k<<1),rc=(k<<1|1);
 64     int mid=((L+R)>>1);
 65     int ls=mid-L,rs=R-mid;
 66     dat[lc]=(dat[lc]+ls*tag[k])%MOD;
 67     dat[rc]=(dat[rc]+rs*tag[k])%MOD;
 68     tag[lc]=(tag[lc]+tag[k])%MOD;
 69     tag[rc]=(tag[rc]+tag[k])%MOD;
 70     tag[k]=0;
 71 }
 72 ll RMQ_query(int a,int b,int k,int L,int R){
 73     if(b<=L||R<=a){
 74         return 0;
 75     }    
 76     else if(a<=L&&R<=b){
 77         return dat[k];
 78     }
 79     else{
 80         if(tag[k]){
 81             pushdown(k,L,R);
 82         }
 83         ll lc=RMQ_query(a,b,k<<1,L,(L+R)>>1);
 84         ll rc=RMQ_query(a,b,k<<1|1,(L+R)>>1,R);
 85         return (lc+rc)%MOD;
 86     }
 87 }
 88 void RMQ_update(int a,int b,int k,int L,int R,ll t){
 89     if(b<=L||R<=a){
 90         return;
 91     }
 92     else if(a<=L&&R<=b){
 93         dat[k]=(dat[k]+(R-L)*t)%MOD;
 94         tag[k]=(tag[k]+t)%MOD;
 95     }
 96     else{
 97         if(tag[k]){
 98             pushdown(k,L,R);
 99         }
100         RMQ_update(a,b,k<<1,L,(L+R)>>1,t);
101         RMQ_update(a,b,k<<1|1,(L+R)>>1,R,t);
102         dat[k]=(dat[k<<1]+dat[k<<1|1])%MOD;
103     }
104 }
105 ll Tree_query(int x,int y){
106     ll ret=0;
107     int f1=top[x],f2=top[y];
108     while(f1!=f2){
109         if(dep[f1]<dep[f2]){
110             swap(x,y);swap(f1,f2);
111         }
112         ll t=RMQ_query(tree[f1],tree[x]+1,1,1,V+1);
113         ret=(ret+t)%MOD;
114         x=fa[f1];f1=top[x];
115     }
116     if(dep[x]<dep[y]){
117         swap(x,y);
118     }
119     ll t=RMQ_query(tree[y],tree[x]+1,1,1,V+1);
120     ret=(ret+t)%MOD;
121     return ret;
122 }
123 void Tree_update(int x,int y,ll t){
124     int f1=top[x],f2=top[y];
125     while(f1!=f2){
126         if(dep[f1]<dep[f2]){
127             swap(x,y);swap(f1,f2);
128         }
129         RMQ_update(tree[f1],tree[x]+1,1,1,V+1,t);
130         x=fa[f1];f1=top[x];
131     }
132     if(dep[x]<dep[y]){
133         swap(x,y);
134     }
135     RMQ_update(tree[y],tree[x]+1,1,1,V+1,t);
136 }
137 void solve1(){
138     int x,y; ll t;
139     scanf("%d%d%lld",&x,&y,&t);
140     Tree_update(x,y,t);
141 }
142 void solve2(){
143     int x,y;
144     scanf("%d%d",&x,&y);
145     ll ans=Tree_query(x,y);
146     printf("%lld\\n",ans);
147 }
148 void solve3(){
149     int x;ll t;
150     scanf("%d%lld",&x,&t);
151     int y=tree[x]+size[x]-1;
152     x=tree[x];
153     RMQ_update(x,y+1,1,1,V+1,t);
154 }
155 void solve4(){
156     int x;
157     scanf("%d",&x);
158     int y=tree[x]+size[x]-1;
159     x=tree[x];
160     ll ans=RMQ_query(x,y+1,1,1,V+1);
161     printf("%lld\\n",ans);
162 }
163 int main()
164 {
165  //   freopen("data.in","r",stdin);
166     int T;
167     scanf("%d%d%d%d",&V,&T,&root,&MOD);
168     for(int i=1;i<=V;i++){
169         scanf("%lld",&Val[i]);
170     }
171     for(int i=1;i<V;i++){
172         int x,y;
173         scanf("%d%d",&x,&y);
174         Add(x,y);
175     }
176     dfs1(root);
177     dfs2(root,root);
178     build(1,1,V+1);
179     for(int i=1;i<=T;i++){
180         int p;
181         scanf("%d",&p);
182         if(1==p){
183             solve1();
184         }
185         else if(2==p){
186             solve2();
187         }
188         else if(3==p){
189             solve3();
190         }
191         else{
192             solve4();
193         }
194     }
195     return 0;
196 }
View Code

模版链接:https://www.luogu.org/problem/show?pid=3384

 

以上是关于树链剖分模版的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 1036 [ZJOI2008]树的统计Count (树链剖分 - 点权剖分 - 单点权修改)

SPOJ - QTREE(树链剖分+单点更新+区间最大值查询)

BZOJ 2243--染色(树链剖分)

树链剖分详解

树链剖分小结

树链剖分详解