[模板]树链剖分

用途

我想把一个本来是线性的东西放到树上做,维护路径或者是子树的各种性质,那就用树剖呗

它可以套线段树、树状数组、ST表(以及其他我不知道的)

做法

我们考虑把树分成一条条链,然后对每条链维护我们的数据结构(线段树等)。对于两点间路径的询问,只要把路径拆成好几条链统计答案就可以了

然后为了保证链数是$O(logn)$的,我们需要把每个点和他的重儿子连成一条链,所谓重儿子,就是节点数最多的儿子

所以做两遍dfs,第一遍求出节点的重儿子、父节点和深度(用于统计答案),第二遍按照重儿子优先的顺序去做dfs序,这样可以保证每条重链连续、而且每个子树连续

我们以这个dfs序为下标,建一棵线段树(或者别的什么)

再记每个链的最靠上的节点是谁,然后查询的时候一直拿着个往上跳就行了

所以每次操作$O(log^2n)$

例题

luogu4114 Qtree1(修改边权、查询路径最大边权)

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 #include<vector>
  5 #include<queue>
  6 #include<cmath>
  7 #include<ctime>
  8 #define LL long long int
  9 #define inf 0x3f3f3f3f
 10 using namespace std;
 11 const int maxn=100010;
 12 
 13 LL rd(){
 14    LL x=0;char c=getchar();int neg=1;
 15    while(c<'0'||c>'9'){if(c=='-') neg=-1;c=getchar();}
 16    while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
 17    return x*neg;
 18 }
 19 
 20 struct Edge{
 21     int a,b,l,ne;
 22 }eg[maxn*2];
 23 int N;
 24 int egh[maxn],ect;
 25 int wson[maxn],fa[maxn],dep[maxn];
 26 int val[maxn],num[maxn],root[maxn],top[maxn],het[maxn];
 27 int ch[maxn*3][2],v[maxn*4],pct;
 28 
 29 inline void adeg(int a,int b,int l){
 30     eg[ect].a=a;eg[ect].b=b;eg[ect].l=l;eg[ect].ne=egh[a];egh[a]=ect++;
 31 }
 32 
 33 int dfs1(int x,int f){
 34     int ma=-inf,mi=0,re=1;fa[x]=f;dep[x]=dep[f]+1;
 35     for(int i=egh[x];i!=-1;i=eg[i].ne){
 36         int b=eg[i].b;if(b==f) continue;
 37         int c=dfs1(b,x);re+=c;
 38         val[b]=max(val[b],eg[i].l);
 39         if(c>ma) ma=c,mi=b;
 40     }wson[x]=mi;return re;
 41 }
 42 
 43 inline void update(int p){v[p]=max(v[ch[p][0]],v[ch[p][1]]);}
 44 
 45 void build(int &p,int l,int r){
 46     p=++pct;if(l==r) v[p]=val[num[l]];
 47     else{
 48         int m=l+r>>1;
 49         build(ch[p][0],l,m);build(ch[p][1],m+1,r);
 50         update(p);
 51     }
 52 }
 53 void change(int p,int l,int r,int x,int y){
 54     if(l==r) v[p]=y;
 55     else{
 56         int m=l+r>>1;
 57         if(x<=m) change(ch[p][0],l,m,x,y);
 58         else change(ch[p][1],m+1,r,x,y);
 59         update(p);
 60     }
 61 }
 62 int query(int p,int l,int r,int x,int y){
 63     if(x<=l&&r<=y) return v[p];
 64     else{
 65         int m=l+r>>1,re=-inf;
 66         if(x<=m) re=max(re,query(ch[p][0],l,m,x,y));
 67         if(y>=m+1) re=max(re,query(ch[p][1],m+1,r,x,y));
 68         return re;
 69     }
 70 }
 71 
 72 void dfs2(int x,int f){
 73     if(wson[f]!=x){int i,j;
 74         for(i=1,j=x;j;j=wson[j],i++) num[i]=j,top[j]=x;
 75         het[x]=i-1;build(root[x],1,het[x]);
 76     }for(int i=egh[x];i!=-1;i=eg[i].ne){
 77         int b=eg[i].b;if(b==f) continue;
 78         dfs2(b,x);
 79     }
 80 }
 81 
 82 void solveC(int a,int b){
 83     int x=eg[a*2-1].a,y=eg[a*2-1].b;
 84     if(dep[x]<dep[y]) swap(x,y);
 85     change(root[top[x]],1,het[top[x]],dep[x]-dep[top[x]]+1,b);
 86 }
 87 
 88 int solveQ(int x,int y){
 89     int re=-inf;if(x==y) return 0;
 90     while(top[x]!=top[y]){
 91         if(dep[top[x]]<dep[top[y]]) swap(x,y);
 92         re=max(re,query(root[top[x]],1,het[top[x]],1,dep[x]-dep[top[x]]+1));
 93         x=fa[top[x]];
 94     }if(x==y) return re;
 95     if(dep[x]>dep[y]) swap(x,y);
 96     return max(re,query(root[top[x]],1,het[top[x]],dep[x]-dep[top[x]]+2,dep[y]-dep[top[x]]+1));
 97 }
 98 
 99 int main(){
100     //freopen("4114.in","r",stdin);
101     int i,j,k;
102     char s[20];
103     N=rd();memset(egh,-1,sizeof(egh));
104     for(i=1;i<N;i++){
105         int a=rd(),b=rd(),c=rd();
106         adeg(a,b,c);adeg(b,a,c);
107     }dfs1(1,0);dfs2(1,0);
108     while(1){
109         scanf("%s",s);if(s[0]=='D') break;
110         i=rd(),j=rd();
111         if(s[0]=='C') solveC(i,j);
112         else printf("%d
",solveQ(i,j));
113     }
114     return 0;
115 }
luogu4114

 suoi23 ZHX知识树 (改路径/子树点权 查路径/子树点权和/最大值)

  1 #include<bits/stdc++.h>
  2 #define pa pair<int,int>
  3 #define CLR(a,x) memset(a,x,sizeof(a))
  4 using namespace std;
  5 typedef long long ll;
  6 const int maxs=2e7,maxn=1e6+5,QS=233333333,QM=114514810;
  7 
  8 inline char gc(){
  9     static char buf[maxs],*p1=buf,*p2=buf;
 10     return p1==p2&&(p2=(p1=buf)+fread(buf,1,maxs,stdin),p1==p2)?EOF:*p1++;
 11 }
 12 
 13 inline ll rd(){
 14     ll x=0;char c=gc();int neg=1;
 15     while(c<'0'||c>'9'){if(c=='-') neg=-1;c=gc();}
 16     while(c>='0'&&c<='9') x=x*10+c-'0',c=gc();
 17     return x*neg;
 18 }
 19 
 20 int eg[maxn*2][2],egh[maxn],ect;
 21 int N,M,root,fa[maxn];
 22 int dep[maxn],wson[maxn],dfn[maxn][2],top[maxn],siz[maxn];
 23 int ch[maxn*4][2],tot,id[maxn];
 24 int pct;
 25 ll sum[maxn*4],ma[maxn*4],laz[maxn*4];
 26 int v[maxn];
 27 
 28 inline void adeg(int a,int b){
 29     eg[++ect][0]=b;eg[ect][1]=egh[a];egh[a]=ect;
 30 }
 31 
 32 inline void update(int p){
 33     if(!ch[p][0]) return;
 34     sum[p]=sum[ch[p][0]]+sum[ch[p][1]];
 35     ma[p]=max(ma[ch[p][0]],ma[ch[p][1]]);
 36 }
 37 
 38 void build(int &p,int l,int r){
 39     if(!p) p=++pct;
 40     if(l==r) sum[p]=ma[p]=v[id[l]];
 41     else{
 42         int m=l+r>>1;
 43         build(ch[p][0],l,m);build(ch[p][1],m+1,r);
 44         update(p);
 45     }
 46 }
 47 
 48 inline void pushdown(int p,int l,int r){
 49     if(!laz[p]) return;
 50     if(l<r){
 51         int a=ch[p][0],b=ch[p][1];
 52         int m=l+r>>1;
 53         laz[a]+=laz[p];
 54         sum[a]+=(m-l+1)*laz[p];
 55         ma[a]+=laz[p];
 56         
 57         laz[b]+=laz[p];
 58         sum[b]+=(r-m)*laz[p];
 59         ma[b]+=laz[p];
 60     }laz[p]=0;
 61 }
 62 
 63 void add(int p,int l,int r,int x,int y,int z){
 64     if(x<=l&&r<=y){
 65         laz[p]+=z;
 66         sum[p]+=(r-l+1)*z;
 67         ma[p]+=z;
 68     }else{
 69         pushdown(p,l,r);
 70         int m=l+r>>1;
 71         if(x<=m) add(ch[p][0],l,m,x,y,z);
 72         if(y>=m+1) add(ch[p][1],m+1,r,x,y,z);
 73         update(p);
 74     }
 75 }
 76 
 77 ll querys(int p,int l,int r,int x,int y){
 78     pushdown(p,l,r);
 79     if(x<=l&&r<=y){
 80         return sum[p];
 81     }else{
 82         int m=l+r>>1;ll re=0;
 83         if(x<=m) re=querys(ch[p][0],l,m,x,y);
 84         if(y>=m+1) re+=querys(ch[p][1],m+1,r,x,y);
 85         return re;
 86     }
 87 }
 88 
 89 void querym(int p,int l,int r,int x,int y,ll &re){
 90     pushdown(p,l,r);
 91     if(x<=l&&r<=y){
 92         re=max(re,ma[p]);
 93     }else{
 94         int m=l+r>>1;
 95         if(x<=m&&ma[ch[p][0]]>re) querym(ch[p][0],l,m,x,y,re);
 96         if(y>=m+1&&ma[ch[p][1]]>re) querym(ch[p][1],m+1,r,x,y,re);
 97     }
 98 }
 99 
100 void dfs1(int x){
101     siz[x]=1;
102     int m=0;
103     for(int i=egh[x];i;i=eg[i][1]){
104         int b=eg[i][0];if(b==fa[x]) continue;
105         dep[b]=dep[x]+1;
106         fa[b]=x;
107         dfs1(b);
108         siz[x]+=siz[b];
109         if(siz[b]>m) m=siz[b],wson[x]=b;
110     }
111 }
112 
113 void dfs2(int x){
114     if(x==wson[fa[x]]) top[x]=top[fa[x]];
115     else top[x]=x;
116     dfn[x][0]=++tot;id[tot]=x;
117     if(wson[x]) dfs2(wson[x]);
118     for(int i=egh[x];i;i=eg[i][1]){
119         int b=eg[i][0];if(b==fa[x]||b==wson[x]) continue;
120         dfs2(b);
121     }
122     dfn[x][1]=tot;
123 }
124 
125 ll solve(int x,int y,int op){
126     ll re=(op==QM?-1e11:0);
127     while(top[x]!=top[y]){
128         if(dep[top[x]]<dep[top[y]]) swap(x,y);
129         if(op==QS){
130             re+=querys(root,1,N,dfn[top[x]][0],dfn[x][0]);
131         }else if(op==QM){
132             querym(root,1,N,dfn[top[x]][0],dfn[x][0],re);
133         }else{
134             add(root,1,N,dfn[top[x]][0],dfn[x][0],op);
135         }
136         x=fa[top[x]];
137     }if(dep[x]<dep[y]) swap(x,y);
138     if(op==QS){
139         re+=querys(root,1,N,dfn[y][0],dfn[x][0]);
140     }else if(op==QM){
141         querym(root,1,N,dfn[y][0],dfn[x][0],re);
142     }else{
143         add(root,1,N,dfn[y][0],dfn[x][0],op);
144     }
145     return re;
146 }
147 
148 int main(){
149     int i;
150     N=rd(),M=rd();
151     for(i=1;i<=N;i++) v[i]=rd();
152     for(i=1;i<N;i++){
153         int a=rd(),b=rd();
154         adeg(a,b);adeg(b,a);
155     }
156     dfs1(1);dfs2(1);
157     build(root,1,N);
158     for(i=1;i<=M;i++){
159         int op=rd(),x=rd();
160         if(op==1){
161             int y=rd(),v=rd();
162             solve(x,y,v);
163         }else if(op==2){
164             int v=rd();
165             add(root,1,N,dfn[x][0],dfn[x][1],v);
166         }else if(op==3){
167             printf("%lld
",querys(root,1,N,dfn[x][0],dfn[x][0]));
168         }else if(op==4){
169             int y=rd();
170             printf("%lld
",solve(x,y,QS));
171         }else if(op==5){
172             printf("%lld
",querys(root,1,N,dfn[x][0],dfn[x][1]));
173         }else if(op==6){
174             int y=rd();
175             printf("%lld
",solve(x,y,QM));
176         }else if(op==7){
177             ll re=-1e12;
178             querym(root,1,N,dfn[x][0],dfn[x][1],re);
179             printf("%lld
",re);
180         }
181     }
182     return 0;
183 }
suoi23
原文地址:https://www.cnblogs.com/Ressed/p/9404318.html