【BJOI2014】大融合 LCT维护子树信息

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

Output

对每个查询操作,输出被查询的边的负载。

Sample Input

8 6
A 2 3
A 3 4
A 3 8
A 8 7
A 6 5
Q 3 8

Sample Output

6

题解
题目大意就是求一条边两端各联通多少点,然后用乘法原理求出答案。
LCT一般用于维护路径,这道题维护子树就让本蒟蒻很为难……
开两个特殊的数组:siz[]记录子树中所有点的个数(包括实边连的点和虚边连的点),cnt[]记录虚边连的点的个数。在ACCESS和更新操作时特别改一下即可。

代码

#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn=1e5+5;
int a,b,n,q,tot,l[maxn],r[maxn],fa[maxn],siz[maxn],cnt[maxn],lazy[maxn];
char op;
bool Isroot(int p)
{
    return l[fa[p]]!=p&&r[fa[p]]!=p;
}
void Update(int x)
{
    siz[x]=siz[l[x]]+siz[r[x]]+cnt[x]+1;
}
void Putdown(int x)
{
    lazy[l[x]]^=1,lazy[r[x]]^=1;
    swap(l[x],r[x]),lazy[x]=0;
}
void Downpath(int x)
{
    if(!Isroot(x)) Downpath(fa[x]);
    if(lazy[x]) Putdown(x);
}
void Zag(int x)
{
    int y=fa[x],z=fa[y];
    if(!Isroot(y))
    {
        if(l[z]==y) l[z]=x;
        else r[z]=x;
    }
    fa[x]=z,r[y]=l[x],fa[l[x]]=y,l[x]=y,fa[y]=x;
    Update(y),Update(x);
}
void Zig(int x)
{
    int y=fa[x],z=fa[y];
    if(!Isroot(y))
    {
        if(l[z]==y) l[z]=x;
        else r[z]=x;
    }
    fa[x]=z,l[y]=r[x],fa[r[x]]=y,r[x]=y,fa[y]=x;
    Update(y),Update(x);
}
void Splay(int x)
{
    Downpath(x);
    while(!Isroot(x))
    {
        int y=fa[x],z=fa[y];
        if(!Isroot(y))
        {
            if(l[z]==y)
            {
                if(l[y]==x) Zig(y),Zig(x);
                else Zag(x),Zig(x);
            }
            else
            {
                if(r[y]==x) Zag(y),Zag(x);
                else Zig(x),Zag(x);
            }
        }
        else
        {
            if(l[y]==x) Zig(x);
            else Zag(x);
        }
    }
}
void Access(int u)
{
    int v=0;
    while(u)
    {
        Splay(u);
        cnt[u]+=siz[r[u]]-siz[v];
        r[u]=v,Update(u);
        v=u,u=fa[u];
    }
}
void Setroot(int p)
{
    Access(p),Splay(p);
    lazy[p]^=1;
}
void Link(int u,int v)
{
    Setroot(u),Setroot(v);
    fa[v]=u,cnt[u]+=siz[v],Update(u);
}
int main()
{
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++) siz[i]=1;
    while(q--)
    {
        scanf("\n%c%d%d",&op,&a,&b);
        if(op=='A') Link(a,b);
        else Setroot(a),Setroot(b),printf("%lld\n",1ll*siz[a]*(siz[b]-siz[a]));
        //for(int i=1;i<=n;i++) printf("%d ",siz[i]);
        //puts("");
    }
    return 0;
}

你可能感兴趣的:(数据结构,--------LCT)