1. 程式人生 > >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\)維護子樹資訊裸題。\(lct\)維護子樹資訊時需要記錄一下虛子樹的資訊和虛子樹+實子樹+自己的資訊。虛子樹資訊只有在\(link\)\(access\)的時候才會被改變。具體看程式碼。

程式碼

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>

using namespace std;
const int MAXN = 100005;
typedef long long LL;

inline int rd(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {f=ch=='-'?0:1;ch=getchar();}
    while(isdigit(ch))  {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return f?x:-x;
}

int n,q,head[MAXN],cnt,to[MAXN<<1],nxt[MAXN<<1];
int siz[MAXN],Siz[MAXN],ch[MAXN][2],fa[MAXN];
bool rev[MAXN];

inline void pushup(int x){
    siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1+Siz[x];
}

inline void pushdown(int x){
    if(rev[x]){
        swap(ch[x][0],ch[x][1]);
        if(ch[x][0]) rev[ch[x][0]]^=1;
        if(ch[x][1]) rev[ch[x][1]]^=1;
        rev[x]=0;
    }
}

inline bool isroot(int x){
    return (x!=ch[fa[x]][0] && x!=ch[fa[x]][1]);
}

void pd(int x){
    if(fa[x]) pd(fa[x]);pushdown(x);
}

inline bool check(int x){
    return (x==ch[fa[x]][1]);
}

inline void rotate(int x){
    int y=fa[x],z=fa[y];bool chk=check(x);
    if(!isroot(y)) ch[z][check(y)]=x;
    ch[y][chk]=ch[x][chk^1];fa[ch[x][chk^1]]=y;
    ch[x][chk^1]=y;fa[y]=x;fa[x]=z;pushup(y);pushup(x);
}

inline void splay(int x){
    pd(x);
    for(;!isroot(x);rotate(x))
        if(!isroot(fa[x])) rotate(check(fa[x])==check(x)?fa[x]:x);
}

inline void access(int x){
    for(int y=0;x;y=x,x=fa[x]){
        splay(x);if(ch[x][1]) Siz[x]+=siz[ch[x][1]];
        if(y) Siz[x]-=siz[y];ch[x][1]=y;pushup(x);
    }
}

inline void makeroot(int x){
    access(x);splay(x);rev[x]^=1;
}

inline void link(int x,int y){
    makeroot(x);makeroot(y);Siz[y]+=siz[x];fa[x]=y;pushup(y);
}

int main(){
    n=rd(),q=rd();char op;int x,y;
    for(int i=1;i<=n;i++) siz[i]=1;
    while(q--){
        cin>>op;x=rd(),y=rd();
        if(op=='A') link(x,y);
        if(op=='Q') {
            makeroot(x);access(y);splay(x);
            printf("%lld\n",(LL)(Siz[y]+1)*(siz[x]-Siz[y]-1));
        }
    }
    return 0;
}