【刷题】BZOJ 4530 [Bjoi2014]大融合

Description

小强要在N个孤立的星球上建立起一套通信系统。这套通信系统就是连接N个点的一个树。

这个树的边是一条一条添加上去的。在某个时刻,一条边的负载就是它所在的当前能够

联通的树上路过它的简单路径的数量。

ff.png

例如,在上图中,现在一共有了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

Solution

LCT的特殊操作——维护子树信息

开个额外的Isize,记录节点虚子树的信息和

然后就裸的题目了

#include<bits/stdc++.h>
#define ll long long
#define db double
#define ld long double
const int MAXN=100000+10;
int n,q;
#define lc(x) ch[(x)][0]
#define rc(x) ch[(x)][1]
struct LCT{
    int ch[MAXN][2],fa[MAXN],rev[MAXN],size[MAXN],Isize[MAXN],stack[MAXN],cnt;
    inline bool nroot(int x)
    {
        return lc(fa[x])==x||rc(fa[x])==x;
    }
    inline void reverse(int x)
    {
        std::swap(lc(x),rc(x));
        rev[x]^=1;
    }
    inline void pushup(int x)
    {
        size[x]=size[lc(x)]+size[rc(x)]+Isize[x]+1;
    }
    inline void pushdown(int x)
    {
        if(rev[x])
        {
            if(lc(x))reverse(lc(x));
            if(rc(x))reverse(rc(x));
            rev[x]=0;
        }
    }
    inline void rotate(int x)
    {
        int f=fa[x],p=fa[f],c=(rc(f)==x);
        if(nroot(f))ch[p][rc(p)==f]=x;
        fa[ch[f][c]=ch[x][c^1]]=f;
        fa[ch[x][c^1]=f]=x;
        fa[x]=p;
        pushup(f);
        pushup(x);
    }
    inline void splay(int x)
    {
        cnt=0;
        stack[++cnt]=x;
        for(register int i=x;nroot(i);i=fa[i])stack[++cnt]=fa[i];
        while(cnt)pushdown(stack[cnt--]);
        for(register int y=fa[x];nroot(x);rotate(x),y=fa[x])
            if(nroot(y))rotate((lc(y)==x)==(lc(fa[y])==y)?y:x);
        pushup(x);
    }
    inline void access(int x)
    {
        for(register int y=0;x;x=fa[y=x])
        {
            splay(x);
            Isize[x]+=size[rc(x)];
            rc(x)=y;
            Isize[x]-=size[rc(x)];
            pushup(x);
        }
    }
    inline void makeroot(int x)
    {
        access(x);splay(x);reverse(x);
    }
    inline void split(int x,int y)
    {
        makeroot(x);access(y);splay(y);
    }
    inline void link(int x,int y)
    {
        makeroot(x);access(y);splay(y);
        fa[x]=y;
        Isize[y]+=size[x];
        pushup(y);
    }
};
LCT T;
#undef lc
#undef rc
template<typename T> inline void read(T &x)
{
    T data=0,w=1;
    char ch=0;
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')w=-1,ch=getchar();
    while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
    x=data*w;
}
template<typename T> inline void write(T x,char c='\0')
{
    if(x<0)putchar('-'),x=-x;
    if(x>9)write(x/10);
    putchar(x%10+'0');
    if(c!='\0')putchar(c);
}
template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
template<typename T> inline T min(T x,T y){return x<y?x:y;}
template<typename T> inline T max(T x,T y){return x>y?x:y;}
int main()
{
    read(n);read(q);
    while(q--)
    {
        char opt[1];int x,y;
        scanf("%s",opt);read(x);read(y);
        if(opt[0]=='A')T.link(x,y);
        if(opt[0]=='Q')
        {
            T.split(x,y);
            write(1ll*(T.size[y]-T.size[x])*T.size[x],'\n');
        }
    }
    return 0;
}

转载于:https://www.cnblogs.com/hongyj/p/8721935.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值