BZOJ 4530: [Bjoi2014]大融合(lct)
阿新 • • 發佈:2018-11-28
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; }