BZOJ:4530: [Bjoi2014]大融合
4530: [Bjoi2014]大融合
拿这题作为lct子树查询的练手。本来以为这会是一个大知识点,结果好像只是一个小技巧?
多维护一个虚边连接着的子树大小即可。
#include<cstdio> #include<cstring> #include<algorithm> #define MN 210010 using namespace std; int p,ca,f; inline int read(){ p=0;ca=getchar();f=1; while(ca<'0'||ca>'9') {if (ca=='-') f=-1;ca=getchar();} while(ca>='0'&&ca<='9') p=p*10+ca-48,ca=getchar(); return p*f; } struct na{ int y,ne,c,nu; }b[MN*2]; int fa[MN],n,t,x,y,c,num,id[MN],key[MN],ch[MN][2],ma[MN],st[MN],Si[MN],si[MN]; bool rt[MN],rev[MN]; inline int max(int a,int b){return a>b?a:b;} inline void up(int x){si[x]=si[ch[x][0]]+si[ch[x][1]]+Si[x]+1;} inline void pd(int x){if (rev[x]) swap(ch[x][0],ch[x][1]),rev[ch[x][0]]^=1,rev[ch[x][1]]^=1,rev[x]=0;} inline void rot(int x){ int y=fa[x],kind=ch[y][1]==x; fa[x]=fa[y]; fa[y]=x; ch[y][kind]=ch[x][!kind]; fa[ch[y][kind]]=y; ch[x][!kind]=y; if(rt[y]) rt[y]=0,rt[x]=1;else ch[fa[x]][ch[fa[x]][1]==y]=x; up(y);up(x); } inline void splay(int x){ int i=x,to=0; while (!rt[i]) st[++to]=i,i=fa[i];pd(i); for (;to;to--) pd(st[to]); while(!rt[x]){ if (rt[fa[x]]) rot(x);else if ((ch[fa[fa[x]]][1]==fa[x])==(ch[fa[x]][1]==x)) rot(fa[x]),rot(x);else rot(x),rot(x); } } inline void acc(int u){ int x=0; while(u){ splay(u); Si[u]+=si[ch[u][1]]-si[x]; rt[ch[u][1]]=1;rt[ch[u][1]=x]=0; up(u); u=fa[x=u]; } } inline void root(int x){acc(x);splay(x);rev[x]^=1;} inline void link(int x,int y){ root(x);acc(y);splay(y); fa[x]=y;Si[y]+=si[x]; } inline int qu(int x,int y){ root(x);acc(y); return (Si[x]+1)*(Si[y]+1); } char ss[10]; int main(){ n=read();t=read(); for (int i=1;i<=n;i++) rt[i]=si[i]=1; while(t--){ scanf("%s",ss); x=read();y=read(); if (ss[0]=='Q') printf("%d\n",qu(x,y));else link(x,y); } }