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;
}
posted @ 2018-07-05 22:02  XSamsara  阅读(81)  评论(0编辑  收藏  举报