P4219 [BJOI2014]大融合

【题意】

很容易简化,就是求断开路径两点后,两点的子树大小之积

【分析】

这种动态加边,删边的操作就很LCT

这是LCT的一类用法,维护子树信息,为什么要单独把维护子树信息拿出来说呢

因为LCT的特点,认父不认子,所以对于子树的信息维护起来是相对有一定难度的

我们多记录一个信息xsiz表示虚儿子的siz大小,考虑什么操作会影响到它,我们发现在link和access发生了轻边的改变,所以在这些位置要注意维护一下xsiz的信息

还有pushup的时候自然siz更新要加上xsiz的部分

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
typedef long long ll;
int n,m;
struct LCT
{
    int son[2],fa,siz,rev,xsiz;
}tr[maxn];
#define ls(x) tr[x].son[0]
#define rs(x) tr[x].son[1]
#define fa(x) tr[x].fa
int q[maxn],len;
void clear(int x)
{
    ls(x)=rs(x)=tr[x].siz=tr[x].xsiz=tr[x].rev=tr[x].fa=0;
}
void pushup(int x)
{
    clear(0);
    if(x) tr[x].siz=tr[ls(x)].siz+tr[rs(x)].siz+1+tr[x].xsiz;
}
void pushdown(int x)
{
    if(!tr[x].rev) return;
    if(ls(x)) swap(ls(ls(x)),rs(ls(x))),tr[ls(x)].rev^=1;
    if(rs(x)) swap(ls(rs(x)),rs(rs(x))),tr[rs(x)].rev^=1;
    tr[x].rev=0;
}
int isroot(int x)
{
    return (ls(fa(x))==x || rs(fa(x))==x);
}
void rotate(int x)
{
    int f=fa(x),ff=fa(f),d=(x==rs(f));
    int w=tr[x].son[d^1];
    tr[f].son[d]=w;
    if(isroot(f)) tr[ff].son[f==rs(ff)]=x;
    tr[x].son[d^1]=f;
    fa(w)=f; fa(f)=x; fa(x)=ff; //这几个一定放到最后!!!要不然对isroot有影响!! 
    pushup(f); pushup(x); pushup(ff);
}
void splay(int x)
{
    q[len=1]=x;
    for(int y=x;isroot(y);y=fa(y)) q[++len]=fa(y);
    for(int i=len;i>=1;i--) pushdown(q[i]);
    while(isroot(x))
    {
        if(isroot(fa(x)))
            rotate(((x==ls(fa(x))) ^ (fa(x)==ls(fa(fa(x)))))?x:fa(x));
        rotate(x);
    }
}
void access(int x)
{
    for(int y=0;x;y=x,x=fa(x))
    {
        splay(x);
        tr[x].xsiz+=tr[rs(x)].siz-tr[y].siz;
        rs(x)=y;
        pushup(x);
    }
}
void makeroot(int x)
{
    access(x);
    splay(x);
    swap(ls(x),rs(x));
    tr[x].rev^=1;
} 
void cut(int x,int y)
{
    makeroot(x);
    access(y);
    splay(y);
    ls(y)=fa(x)=0;
    pushup(x);
}
void link(int x,int y)
{
    makeroot(x); makeroot(y);
    fa(x)=y;
    tr[y].xsiz+=tr[x].siz;
}
int main()
{
//    freopen("mix.in","r",stdin);
    //freopen("mix.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        char s[5];
        int x,y;
        scanf("%s",s);
        scanf("%d%d",&x,&y);
        if(s[0]=='A')
            link(x,y);
        else
        {
            cut(x,y);
            makeroot(x); makeroot(y);
            ll ans=1LL*tr[x].siz*tr[y].siz;
            printf("%lld\n",ans);
            link(x,y);
        }
    }
    return 0;
}

 

rotate认父亲的位置写早了,导致isroot出锅了,调了半天qwq

posted @ 2021-04-25 23:32  andyc_03  阅读(42)  评论(0编辑  收藏  举报