树链剖分
定义:
siz[]数组,用来保存以x为根的子树节点个数
top[]数组,用来保存当前节点的所在链的顶端节点
hson[]数组,用来保存重儿子
drep[]数组,用来保存当前节点的深度
fa[]数组,用来保存当前节点的父亲
id[]数组,用来保存树中每个节点剖分后的新编号
两遍dfs求出以上信息,连边成重链,按照新的编号建树(有的题目这一步可省略);剩下全是线段树的操作
查询或修改的话,因为在第二个dfs中优先构造重链,所以修改深度更深的x到top[x],x再换为fa[x],直到两点top相等;
一般链剖100多行,我强力缩行到87行。。。。。。。。
#include<iostream> #include<cstdlib> #include<cstring> #include<cstdio> #include<algorithm> #include<queue> #define rs ((o<<1)|1) #define ls (o<<1) #define MAXX 300010 using namespace std; struct data{ int nxt,to; }edge[MAXX*2]; int segtree[MAXX*4],head[MAXX],top[MAXX],siz[MAXX],hson[MAXX],id[MAXX]; int n,f,t,m,deep[MAXX],fa[MAXX],lazy[MAXX*4],tot,sm,a,b; void add(int fro,int too){edge[++tot].nxt=head[fro];edge[tot].to=too;head[fro]=tot;} void dfs1(int num,int father){ hson[num]=0;deep[num]=deep[father]+1;siz[num]=1;fa[num]=father; for(int i=head[num];i;i=edge[i].nxt)if(father!=edge[i].to){ int too=edge[i].to; dfs1(too,num); siz[num]+=siz[too]; if(siz[hson[num]]<siz[too])hson[num]=too; } } void dfs2(int num,int toop){ id[num]=++sm;top[num]=toop; if(hson[num])dfs2(hson[num],toop); for(int i=head[num];i;i=edge[i].nxt)if(edge[i].to!=hson[num]&&edge[i].to!=fa[num])dfs2(edge[i].to,edge[i].to); } void down(int o,int l,int r){ int mid=(r+l)>>1; segtree[ls]+=(mid-l+1)*lazy[o],segtree[rs]+=lazy[o]*(r-mid); lazy[rs]+=lazy[o],lazy[ls]+=lazy[o],lazy[o]=0; } void update(int o,int L,int R,int ll,int rr){ if(L!=R)down(o,L,R); if(L>=ll&&R<=rr){segtree[o]+=(R-L+1);lazy[o]++;return;} int mid=(L+R)>>1; if(mid<ll)update(rs,mid+1,R,ll,rr); else if(mid>=rr)update(ls,L,mid,ll,rr); else update(ls,L,mid,ll,rr),update(rs,mid+1,R,ll,rr); segtree[o]=segtree[ls]+segtree[rs]; } int ask(int o,int L,int R,int ll,int rr){ if(L!=R)down(o,L,R); if(L>=ll&&R<=rr)return segtree[o]; int mid=(L+R)>>1; if(mid<ll)return ask(rs,mid+1,R,ll,rr); else if(mid>=rr)return ask(ls,L,mid,ll,rr); else return ask(ls,L,mid,ll,rr)+ask(rs,mid+1,R,ll,rr); } void work1(int x,int y){ while(top[x]!=top[y]){ if(deep[top[x]]<deep[top[y]])swap(x,y); update(1,1,n,id[top[x]],id[x]); x=fa[top[x]]; } if(deep[x]>deep[y])swap(x,y); update(1,1,n,id[x],id[y]); } int work2(int x,int y){ int ans=0; while(top[x]!=top[y]){ if(deep[top[x]]<deep[top[y]])swap(x,y); ans+=ask(1,1,n,id[top[x]],id[x]); x=fa[top[x]]; } if(deep[x]>deep[y])swap(x,y); ans+=ask(1,1,n,id[x],id[y]); return ans; } int main(){ freopen("1.in","r",stdin); freopen("1.out","w",stdout); scanf("%d",&n); for(int i=1;i<n;++i)scanf("%d%d",&f,&t),add(f,t),add(t,f); dfs1(1,0),dfs2(1,1); scanf("%d",&m); for(int i=1;i<=m;++i){ int c; scanf("%d%d%d",&c,&a,&b); if(c==1)work1(a,b); else printf("%d\n",work2(a,b)); } return 0; }