BZOJ_4530_[Bjoi2014]大融合_LCT

BZOJ_4530_[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维护的是一些链的信息。

splay的根不一定连向树上的儿子,这样丢失了儿子的信息。因此无法维护子树信息。

需要在一些操作中加入对子树信息的变动。

设all[x]为x子树结点个数,siz[x]为x子树不在链上结点个数。

注意到access操作割掉了rs加入了t,因此不在链上结点个数需要加rs减去t。

然后link操作也改变了子树信息,需要对两个结点分别更新,makeroot两次即可。

上传函数也改一下。

 

代码:

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define N 100050
#define ls ch[p][0]
#define rs ch[p][1]
#define get(x) (ch[f[x]][1]==x)
int ch[N][2],f[N],rev[N],siz[N],all[N],n,m;
char opt[10];
inline bool isrt(int p) {
    return ch[f[p]][0]!=p&&ch[f[p]][1]!=p;
}
inline void pushdown(int p) {
    if(rev[p]) {
        swap(ch[ls][0],ch[ls][1]); swap(ch[rs][0],ch[rs][1]);
        rev[ls]^=1; rev[rs]^=1; rev[p]=0;
    }
}
inline void pushup(int p) {
    all[p]=all[ls]+all[rs]+siz[p]+1;
}
void update(int p) {
    if(!isrt(p)) update(f[p]);
    pushdown(p);
}
void rotate(int x) {
    int y=f[x],z=f[y],k=get(x);
    if(!isrt(y)) ch[z][ch[z][1]==y]=x;
    ch[y][k]=ch[x][!k]; f[ch[y][k]]=y;
    ch[x][!k]=y; f[y]=x; f[x]=z;
    pushup(y); pushup(x);
}
void splay(int x) {
    update(x);
    for(int fa;fa=f[x],!isrt(x);rotate(x))
        if(!isrt(fa))
            rotate(get(fa)==get(x)?fa:x);
}
void access(int p) {
    int t=0;
    while(p) splay(p),siz[p]+=all[rs]-all[t],rs=t,pushup(p),t=p,p=f[p];
}
void makeroot(int p) {
    access(p); splay(p); swap(ls,rs); rev[p]^=1;
}
void link(int x,int p) {
    makeroot(x); makeroot(p); f[x]=p; siz[p]+=all[x]; pushup(p);
}
int main() {
    scanf("%d%d",&n,&m);
    int i,x,y;
    for(i=1;i<=n;i++) all[i]=1;
    for(i=1;i<=m;i++) {
        scanf("%s%d%d",opt,&x,&y);
        if(opt[0]=='A') {
            link(x,y);
        }else {
            makeroot(x); makeroot(y);
            printf("%lld\n",1ll*all[x]*(all[y]-all[x]));
        }
    }
}

 

posted @ 2018-04-29 22:13  fcwww  阅读(197)  评论(0编辑  收藏  举报