树链剖分模版
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 }
模版链接:https://www.luogu.org/problem/show?pid=3384
以上是关于树链剖分模版的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ 1036 [ZJOI2008]树的统计Count (树链剖分 - 点权剖分 - 单点权修改)