bzoj 4530 [Bjoi2014]大融合——LCT维护子树信息
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4530
LCT维护子树 siz 。设 sm[ ] 表示轻儿子的 siz 和+1(1是自己的siz),siz[ ] 表示 splay 里 ( 两个儿子的 siz[ ] ) + sm[ cr ] 。在 access 里随便维护一下就好了。
一开始写的 siz[ ] 是 splay 里右儿子的 siz[ ] + sm[ cr ] ,但打 rev[ ] 的时候难以维护,所以弃了。
注意要先让一个点作为 splay 的根,再给它连右儿子,才能比较好地维护好;所以 link( ) 的时候注意 access( y ) !
#include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const int N=1e5+5; int n,Q,fa[N],c[N][2],siz[N],sm[N]; int sta[N],top;bool rev[N]; int rdn() { int ret=0;bool fx=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();} while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar(); return fx?ret:-ret; } bool isroot(int x){return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;} void pshp(int x){siz[x]=sm[x]+siz[c[x][0]]+siz[c[x][1]];} void Rev(int x) { if(!rev[x])return;rev[x]=0; rev[c[x][0]]^=1;rev[c[x][1]]^=1; swap(c[x][0],c[x][1]); } void rotate(int x) { int y=fa[x],z=fa[y],d=(x==c[y][1]); if(!isroot(y))c[z][y==c[z][1]]=x; fa[x]=z; fa[y]=x;fa[c[x][!d]]=y; c[y][d]=c[x][!d];c[x][!d]=y; pshp(y);pshp(x); } void splay(int x) { sta[top=1]=x; for(int k=x;!isroot(k);k=fa[k])sta[++top]=fa[k]; for(int i=top;i;i--)Rev(sta[i]); int y,z; while(!isroot(x)) { y=fa[x];z=fa[y]; if(!isroot(y)) ((x==c[y][0])^(y==c[z][0]))?rotate(x):rotate(y); rotate(x); } } void access(int x) { int t=0; while(x) { splay(x); sm[x]+=siz[c[x][1]]; sm[x]-=siz[t]; c[x][1]=t; pshp(x);///// t=x;x=fa[x]; } } void makeroot(int x) { access(x);splay(x);rev[x]^=1; } void link(int x,int y) { makeroot(x);access(y);splay(y);//access()!!! fa[x]=y;sm[y]+=siz[x];siz[y]+=siz[x]; } ll query(int x,int y) { makeroot(x);access(y);splay(y); return (ll)siz[x]*sm[y]; } int main() { n=rdn();Q=rdn(); for(int i=1;i<=n;i++)siz[i]=1,sm[i]=1; int x,y;char ch[3]; while(Q--) { scanf("%s",ch);x=rdn();y=rdn(); if(ch[0]=='A')link(x,y); else printf("%lld\n",query(x,y)); } return 0; }