BZOJ4530 BJOI 2014 大融合 LCT维护子树信息

BZOJ4530 大融合

Description

小强要在N个孤立的星球上建立起一套通信系统。这套通信系统就是连接N个点的一个树。
这个树的边是一条一条添加上去的。在某个时刻,一条边的负载就是它所在的当前能够
联通的树上路过它的简单路径的数量。
例如,在上图中,现在一共有了5条边。其中,(3,8)这条边的负载是6,因
为有六条简单路径2-3-8,2-3-8-7,3-8,3-8-7,4-3-8,4-3-8-7路过了(3,8)。
现在,你的任务就是随着边的添加,动态的回答小强对于某些边的负载的
询问。

Input

第一行包含两个整数N,Q,表示星球的数量和操作的数量。星球从1开始编号。
接下来的Q行,每行是如下两种格式之一:
A x y 表示在x和y之间连一条边。保证之前x和y是不联通的。
Q x y 表示询问(x,y)这条边上的负载。保证x和y之间有一条边。
1≤N,Q≤100000


题目中要求的负载就是以一条边端点为根的两个子树的大小相乘。而动态加边的操作很容易想到LCT。一般的LCT通过伸展树维护的是一条链上的信息,但这并不意味着不能使用LCT。

开两个数组 Size[x] sz[x] ,分别表示以 x 为根的子树的大小、 x 的虚儿子的 Size 和。那么有递推式:

Size[x]=Size[ls[x]]+Size[rs[x]]+1+sz[x]

也就是把 Size 划分为了伸展树里节点的 Size 之和、虚儿子的 Size 之和。那么现在的问题在于如何维护 sz 数组。注意到本题用到的 Access 操作中,每次向上跳都最多只会将一条实边改为虚边、一条虚边改为实边; Link 操作直接是给一个点增加一个虚儿子。所以在这两个操作中维护一下 sz 即可。


#include
#include
#define MAXN 200005
#define ll long long
using namespace std;

int N,Q;

int ls[MAXN],rs[MAXN],fa[MAXN],rev[MAXN],Size[MAXN],sz[MAXN];

bool isrt(int x){return ls[fa[x]]!=x&&rs[fa[x]]!=x;}

void Update(int p)
{
    Size[p]=Size[ls[p]]+Size[rs[p]]+sz[p]+1;
    //Size[p]=Size[rs[p]]+sz[p]+1;
}

void Putdown(int p)
{
    if(rev[p]==0)return;
    rev[p]=0;rev[ls[p]]^=1;rev[rs[p]]^=1;
    swap(ls[p],rs[p]);
}

void Zig(int x)
{
    int y=fa[x],z=fa[y];
    if(!isrt(y))
    {
        if(ls[z]==y)ls[z]=x;
        else rs[z]=x;
    }
    fa[x]=z;fa[y]=x;fa[rs[x]]=y;
    ls[y]=rs[x];rs[x]=y;
    Update(y);Update(x);
}

void Zag(int x)
{
    int y=fa[x],z=fa[y];
    if(!isrt(y))
    {
        if(ls[z]==y)ls[z]=x;
        else rs[z]=x;
    }
    fa[x]=z;fa[y]=x;fa[ls[x]]=y;
    rs[y]=ls[x];ls[x]=y;
    Update(y);Update(x);
}

int s[MAXN],Top;

void Splay(int x)
{
    int i,y,z;

    s[++Top]=x;
    for(i=x;!isrt(i);i=fa[i])s[++Top]=fa[i];
    while(Top)Putdown(s[Top--]);

    while(!isrt(x))
    {
        y=fa[x];z=fa[y];
        if(isrt(y))
        {
            if(ls[y]==x)Zig(x);
            else Zag(x);
        }
        else
        {
            if(ls[z]==y)
            {
                if(ls[y]==x)Zig(y),Zig(x);
                else Zag(x),Zig(x);
            }
            else
            {
                if(rs[y]==x)Zag(y),Zag(x);
                else Zig(x),Zag(x);
            }
        }
    }
}

void Access(int x)
{
    int t=0;
    while(x)
    {
        Splay(x);
        sz[x]=sz[x]-Size[t]+Size[rs[x]];
        rs[x]=t;
        Update(x);
        t=x;x=fa[x];
    }
}

void SetRt(int x)
{
    Access(x);Splay(x);rev[x]^=1;
}

void Link(int x,int y)
{
    SetRt(x);SetRt(y);
    sz[y]+=Size[x];
    Update(y);
    Splay(y);
    fa[x]=y;
}

int main()
{
    int i,x,y;
    char op[3];
    ll Ans;

    scanf("%d%d",&N,&Q);
    for(i=1;i<=N;i++)Size[i]=1;

    while(Q--)
    {
        scanf("%s%d%d",op,&x,&y);
        if(op[0]=='A')Link(x,y);
        else
        {
            SetRt(x);Access(y);
            Ans=sz[y]+1;
            SetRt(y);Access(x);
            Ans*=(sz[x]+1);
            printf("%lld\n",Ans);
        }
    }
}

你可能感兴趣的:(LCT)