Link-cut tree(LCT)【可以理解为树链剖分+splay】
给出如下定义:
access(x):访问x节点
perferred child:若以x为根的子树中最后被访问的节点在以x的儿子y为根的子树中,则称y为节点x的preferred child
preferred edge:节点x与其preferred child之间的边
preferred path:由preferred edge组成的路径
每条preferred path用splay维护,记录splay的根接到上条重链的哪个节点
操作
每次访问一个点时,该点一直到根的路径上的点全部被修改,与preferred child断开并连到新的preferred child上,并打上翻转标记,也就是拆分(cut)和合并(link)两个操作,其余链上的维护可以通过下传标记(pushdown)解决
例题:
bzoj2002弹飞绵羊
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> using namespace std; const int Mx=200010; int n,m,fa[Mx],l[Mx],r[Mx],root[Mx],siz[Mx],rev[Mx]; void pushup(int x) { siz[x]=siz[l[x]]+siz[r[x]]+1; } void pushdown(int x) { if(rev[x]) rev[x]^=1,rev[l[x]]^=1,rev[r[x]]^=1,swap(l[x],r[x]); } void rotate(int x) { int y=fa[x]; if(l[y]==x) l[y]=r[x],fa[r[x]]=y,r[x]=y,fa[x]=fa[y],fa[y]=x; else r[y]=l[x],fa[l[x]]=y,l[x]=y,fa[x]=fa[y],fa[y]=x; if(root[y]) root[y]=0,root[x]=1; else if(r[fa[x]]==y) r[fa[x]]=x; else l[fa[x]]=x; pushup(y); } void splay(int x) { while(!root[x]) { int y=fa[x],yy=fa[y]; if(root[y]) rotate(x); else if((l[yy]==y&&l[y]!=x)||(l[yy]!=y&&l[y]==x)) rotate(y),rotate(x); else rotate(x),rotate(x); } pushup(x); } void access(int x) { int y=0; while(x) { splay(x); root[r[x]]=1,root[y]=0; pushup(x); r[x]=y,y=x,x=fa[x]; } } void rever(int x) { access(x); splay(x); rev[x]^=1; } void link(int x,int y) { rever(x); fa[l[x]]=0,root[l[x]]=1,l[x]=0,fa[x]=y; pushup(x); } void cut(int x,int y) { rever(x); access(y); splay(y); l[y]=0,fa[x]=0; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) root[i]=1,siz[i]=1; for(int i=1;i<=n;i++) { int x; scanf("%d",&x); if(i+x<=n) link(i,i+x); } scanf("%d",&m); while(m--) { int num,x,k; scanf("%d",&num); if(num==1) { scanf("%d",&x); x++; rever(x); printf("%d ",siz[l[x]]+1); } else { scanf("%d%d",&x,&k); x++; if(x+k>n) link(x,0); else link(x,x+k); } } }
bzoj2631 tree
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> using namespace std; const int Mx=200010; const int p=51061; int n,top,q[Mx],fa[Mx],son[Mx][2],siz[Mx],rev[Mx]; unsigned int val[Mx],sum[Mx],add_tag[Mx],mul_tag[Mx]; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } void cal(int x,int a,int b) { if(!x) return ; val[x]=(a*val[x]+b)%p; sum[x]=(a*sum[x]+b*siz[x])%p; add_tag[x]=(a*add_tag[x]+b)%p; mul_tag[x]=(a*mul_tag[x])%p; } int isroot(int x) { if(son[fa[x]][0]!=x&&son[fa[x]][1]!=x) return 1; return 0; } void pushup(int x) { int l=son[x][0],r=son[x][1]; sum[x]=(sum[l]+sum[r]+val[x])%p; siz[x]=(siz[l]+siz[r]+1)%p; } void pushdown(int x) { int l=son[x][0],r=son[x][1]; if(rev[x]) rev[x]^=1,rev[l]^=1,rev[r]^=1, swap(son[x][0],son[x][1]); int a=add_tag[x],m=mul_tag[x]; add_tag[x]=0,mul_tag[x]=1; if(a!=0||m!=1) cal(l,m,a),cal(r,m,a); } void rotate(int x) { int l=0,r=0,y=fa[x],yy=fa[y]; if(son[y][1]==x) l=1; r=l^1; if(!isroot(y)) son[yy][(son[yy][1]==y)]=x; fa[x]=yy,fa[y]=x,fa[son[x][r]]=y,son[y][l]=son[x][r],son[x][r]=y; pushup(y);pushup(x); } void splay(int x) { q[++top]=x; for(int i=x;!isroot(i);i=fa[i]) q[++top]=fa[i]; while(top) pushdown(q[top--]); while(!isroot(x)) { int y=fa[x],yy=fa[y]; if(!isroot(y)) { if((son[y][0]==x)^(son[yy][0]==y)) rotate(x); else rotate(y); } rotate(x); } } void access(int x) { for(int t=0;x;t=x,x=fa[x]) splay(x),son[x][1]=t,pushup(x); } void rever(int x) { access(x); splay(x); rev[x]^=1; } void link(int x,int y) { rever(x); fa[x]=y; } void split(int x,int y) { rever(y); access(x); splay(x); } void cut(int x,int y) { rever(x); access(y); splay(y); son[y][0]=fa[x]=0; } signed main() { int m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) val[i]=sum[i]=mul_tag[i]=siz[i]=1; for(int i=1,x,y;i<n;i++) scanf("%d%d",&x,&y),link(x,y); while(m--) { char ch[10]; scanf("%s",ch); int x,y,c; x=read(),y=read(); if(ch[0]=='+') c=read(),split(x,y),cal(x,1,c); if(ch[0]=='-') cut(x,y),x=read(),y=read(),link(x,y); if(ch[0]=='*') c=read(),split(x,y),cal(x,c,0); if(ch[0]=='/') split(x,y),printf("%d ",sum[x]); } return 0; }