bzoj 4530: [Bjoi2014]大融合【LCT】

新姿势,一般来讲LCT只能维护splay重边里的数据,而这里要求维护整颗子树的size
多维护一个sq表示当前点轻儿子的size和,si表示包括轻重边的整颗子树的大小
然后需要改sq的地方是link和access,link是因为给y下面挂了个连着虚边的x点,所以给y的sq加上x的size;acc是改变了splay的结构,把一条实边变虚,一条虚边变实,这样就需要在当前点的sq上加一个size减一个size
然后update需要稍微改一下,其他的就是LCT的板子

#include<iostream>
#include<cstdio>
using namespace std;
const int N=300005;
int n,q,s[N],top;
char o[5];
struct qwe
{
    int c[2],f,si,sq,lz;
}t[N];
int read()
{
    int r=0,f=1;
    char p=getchar();
    while(p>'9'||p<'0')
    {
        if(p=='-')
            f=-1;
        p=getchar();
    }
    while(p>='0'&&p<='9')
    {
        r=r*10+p-48;
        p=getchar();
    }
    return r*f;
}
void pd(int x)
{
    if(t[x].lz)
    {
        swap(t[x].c[0],t[x].c[1]);
        t[t[x].c[0]].lz^=1;
        t[t[x].c[1]].lz^=1;
        t[x].lz=0;
    }
}
void ud(int x)
{
    t[x].si=t[t[x].c[0]].si+t[t[x].c[1]].si+1+t[x].sq;
}
bool srt(int x)
{
    return t[t[x].f].c[0]!=x&&t[t[x].f].c[1]!=x;
}
void zhuan(int x)
{
    int y=t[x].f,z=t[y].f,l=(t[y].c[0]!=x),r=l^1;
    if(!srt(y))
        t[z].c[t[z].c[0]!=y]=x;
    t[x].f=z;
    t[y].c[l]=t[x].c[r];
    t[t[y].c[l]].f=y;
    t[x].c[r]=y;
    t[y].f=x;
    ud(y);
    ud(x);
}
void splay(int x)
{
    top=0;
    s[++top]=x;
    for(int i=x;!srt(i);i=t[i].f)
        s[++top]=t[i].f;
    while(top)
        pd(s[top--]);
    while(!srt(x))
    {
        int y=t[x].f,z=t[x].f;
        if(!srt(y))
        {
            if((t[y].c[0]==x)^(t[z].c[0]==y))
                zhuan(x);
            else
                zhuan(y);
        }
        zhuan(x);
    }
}
void acc(int x)
{
    for(int i=0;x;i=x,x=t[x].f)
    {
        splay(x);
        t[x].sq=t[x].sq+t[t[x].c[1]].si-t[i].si;
        t[x].c[1]=i;
        ud(x);
    }
}
void mkrt(int x)
{
    acc(x);
    splay(x);
    t[x].lz^=1;
}
void lk(int x,int y)
{
    mkrt(x);
    acc(y);
    splay(y);
    t[x].f=y;
    t[y].sq+=t[x].si;
    ud(y);
}
int main()
{
    n=read(),q=read();
    for(int i=1;i<=n;i++)
        t[i].si=1;
    while(q--)
    {
        scanf("%s",o+1);
        int x=read(),y=read();
        if(o[1]=='A')
            lk(x,y);
        else
        {
            mkrt(x);
            acc(y);
            splay(y);
            printf("%lld\n",1ll*t[x].si*(t[y].si-t[x].si));
        }
    }
    return 0;
}
上一篇:2.2.3-4


下一篇:[BZOJ4456][ZJOI2016]旅行者:分治+最短路