BZOJ 4530: [Bjoi2014]大融合【LCT】
4530: [Bjoi2014]大融合
【题目描述】
传送门
【题解】
我们需要维护两个值,子树的信息(W[])和虚儿子(a[])的信息。
void PushUp(int x){if(x) W[x]=W[Son[x][0]]+W[Son[x][1]]+a[x]+1;}
然后我们需要在Access中更新这个a[]的值。
void Access(int x){
for(int t=0;x;t=x,x=Fa[x]){
Splay(x);
a[x]+=W[Son[x][1]]-W[t];//加上原来右儿子的信息,减去新的右儿子信息
Son[x][1]=t;
PushUp(x);
}
}
然后在连接的时候,像并查集一样赋值就可以了。
void Lnk(int x,int y){MakeRoot(x);MakeRoot(y);Fa[x]=y;a[y]+=W[x];PushUp(y);}
记住,不要忘了更新之后要PushUp()。
代码如下
#include<cstdio>
#include<cctype>
#include<algorithm>
#define MAXN 100005
using namespace std;
int n,m;
int read(){
int ret=0;char ch=getchar();bool f=1;
for(;!isdigit(ch);ch=getchar()) f^=!(ch^'-');
for(; isdigit(ch);ch=getchar()) ret=(ret<<3)+(ret<<1)+ch-48;
return f?ret:-ret;
}
struct Link_Cut_Tree{
int Top,Rtd[MAXN],Son[MAXN][2],que[MAXN],Fa[MAXN],W[MAXN],a[MAXN];
void PushUp(int x){if(x) W[x]=W[Son[x][0]]+W[Son[x][1]]+a[x]+1;}
void PushDown(int x){
if(!x) return ;
int &L=Son[x][0],&R=Son[x][1];
if(Rtd[x]){
Rtd[L]^=1;Rtd[R]^=1;Rtd[x]^=1;
swap(L,R);
}
}
int Get(int x){return Son[Fa[x]][1]==x;}
bool IsRoot(int x){return Son[Fa[x]][0]!=x&&Son[Fa[x]][1]!=x;}
void Rotate(int x){
int y=Fa[x],z=Fa[y],L,R;
R=(L=Get(x))^1;
if(!IsRoot(y)) Son[z][Son[z][1]==y]=x;
Fa[y]=x;Fa[x]=z;Fa[Son[x][R]]=y;
Son[y][L]=Son[x][R];Son[x][R]=y;
PushUp(y);PushUp(x);
}
void Splay(int x){
que[Top=1]=x;
for(int i=x;!IsRoot(i);i=Fa[i]) que[++Top]=Fa[i];
for(int i=Top;i;i--) PushDown(que[i]);
while(!IsRoot(x)){
int y=Fa[x],z=Fa[y];
if(!IsRoot(y)) (Son[y][0]==x)^(Son[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);
a[x]+=W[Son[x][1]]-W[t];
Son[x][1]=t;
PushUp(x);
}
}
void MakeRoot(int x){Access(x);Splay(x);Rtd[x]^=1;}
void Lnk(int x,int y){MakeRoot(x);MakeRoot(y);Fa[x]=y;a[y]+=W[x];PushUp(y);}
long long Query(int x,int y){
MakeRoot(x);MakeRoot(y);return (long long)W[x]*(W[y]-W[x]);
}
}Tre;
int main(){
#ifndef ONLINE_JUDGE
freopen("4530.in","r",stdin);
freopen("4530.out","w",stdout);
#endif
n=read(),m=read();
for(int i=1;i<=n;i++) Tre.W[i]=1;
for(int i=1;i<=m;i++){
char ch[10];int x,y;
scanf("%s",ch);
x=read(),y=read();
if(ch[0]=='A') Tre.Lnk(x,y);
else printf("%lld\n",Tre.Query(x,y));
}
return 0;
}