bzoj 4530 大融合 —— LCT维护子树信息
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4530
用LCT维护子树 size,就是实边和虚边分开维护;
看博客:https://blog.csdn.net/neither_nor/article/details/52979425
代码如下:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; int const xn=1e5+5; int n,fa[xn],siz[xn],lt[xn],c[xn][2],sta[xn],top,rev[xn]; int rd() { int ret=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();} while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar(); return f?ret:-ret; } bool isroot(int x){return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;} void pushup(int x){siz[x]=lt[x]+siz[c[x][0]]+siz[c[x][1]]+1;}// void rotate(int x) { int y=fa[x],z=fa[y],d=(c[y][1]==x); if(!isroot(y))c[z][c[z][1]==y]=x; fa[x]=z; fa[y]=x; fa[c[x][!d]]=y; c[y][d]=c[x][!d]; c[x][!d]=y; pushup(y); pushup(x); } void rever(int x){rev[x]^=1; swap(c[x][0],c[x][1]);} void psd(int x) { if(!rev[x])return; rever(c[x][0]); rever(c[x][1]); rev[x]=0; } void splay(int x) { sta[top=1]=x; for(int i=x;!isroot(i);i=fa[i])sta[++top]=fa[i]; while(top)psd(sta[top--]); while(!isroot(x)) { int y=fa[x],z=fa[y]; if(!isroot(y)) ((c[y][0]==x)^(c[z][0]==y))?rotate(x):rotate(y); rotate(x); } } void access(int x) { for(int t=0;x;t=x,x=fa[x]) { splay(x); //if(c[x][1])siz[x]-=siz[c[x][1]],lt[x]+=siz[c[x][1]]; if(c[x][1])lt[x]+=siz[c[x][1]]; c[x][1]=t; //if(t)siz[x]+=siz[t],lt[x]-=siz[t]; if(t)lt[x]-=siz[t]; pushup(x); } } void makeroot(int x) { access(x); splay(x); rever(x); } void link(int x,int y) { makeroot(x); access(y); splay(y); fa[x]=y; lt[y]+=siz[x]; pushup(y); } char dc[3]; int main() { n=rd(); int m=rd(); for(int i=1,x,y;i<=m;i++) { scanf("%s",dc); x=rd(); y=rd(); if(dc[0]=='A')link(x,y); else { makeroot(x); access(y); splay(y); printf("%lld\n",(ll)(siz[y]-siz[x])*siz[x]); } } return 0; }