洛谷 P4219 [BJOI2014]大融合 解題報告
阿新 • • 發佈:2018-12-07
P4219 [BJOI2014]大融合
題目描述
小強要在\(N\)個孤立的星球上建立起一套通訊系統。這套通訊系統就是連線\(N\)個點的一個樹。 這個樹的邊是一條一條新增上去的。在某個時刻,一條邊的負載就是它所在的當前能夠 聯通的樹上路過它的簡單路徑的數量。
現在,你的任務就是隨著邊的新增,動態的回答小強對於某些邊的負載的 詢問。
輸入輸出格式
輸入格式:
第一行包含兩個整數 \(N, Q\),表示星球的數量和操作的數量。星球從 \(1\) 開始編號。
接下來的 \(Q\) 行,每行是如下兩種格式之一:
A x y
表示在 \(x\) 和 \(y\) 之間連一條邊。保證之前 \(x\)Q x y
表示詢問 \((x,y)\) 這條邊上的負載。保證 \(x\) 和 \(y\) 之間有一條邊。
輸出格式:
對每個查詢操作,輸出被查詢的邊的負載。
說明
對於所有資料,\(1≤N,Q≤10^5\)
LCT維護子樹資訊,漲見識了。
\(sizx_i\)代表虛邊連的兒子的大小。
然後\(updata\)這樣寫
void updata(int now){siz[now]=siz[ls]+siz[rs]+sizx[now]+1;}
然後是在\(access\)的時候修改一下虛邊兒子大小,在\(link\)的時候要把兩個樹都選上去保證沒得父親,因為我們不想把被連的那個點的資訊再向上更新。
維護最值可以在每個點開個平衡樹
Code:
#include <cstdio> #define ll long long #define ls ch[now][0] #define rs ch[now][1] #define fa par[now] const int N=1e5+10; int ch[N][2],par[N],siz[N],sizx[N],tag[N],s[N],tot,tmp; bool isroot(int now){return ch[fa][0]==now||ch[fa][1]==now;} int identity(int now){return ch[fa][1]==now;} void updata(int now){siz[now]=siz[ls]+siz[rs]+sizx[now]+1;} void Reverse(int now){tag[now]^=1,tmp=ls,ls=rs,rs=tmp;} void connect(int f,int now,int typ){ch[fa=f][typ]=now;} void pushdown(int now) { if(tag[now]) { if(ls) Reverse(ls); if(rs) Reverse(rs); tag[now]^=1; } } void Rotate(int now) { int p=fa,typ=identity(now); connect(p,ch[now][typ^1],typ); if(isroot(p)) connect(par[p],now,identity(p)); else fa=par[p]; connect(now,p,typ^1); updata(p),updata(now); } void splay(int now) { while(isroot(now)) s[++tot]=now,now=fa; s[++tot]=now; while(tot) pushdown(s[tot--]); now=s[1]; for(;isroot(now);Rotate(now)) if(isroot(fa)) Rotate(identity(now)^identity(fa)?now:fa); } void access(int now) { for(int las=0;now;las=now,now=fa) splay(now),sizx[now]+=siz[rs]-siz[las],rs=las; } void evert(int now){access(now),splay(now),Reverse(now);} void link(int u,int v){evert(u),access(v),splay(v),par[u]=v,sizx[v]+=siz[u],updata(v);} void cat(int u,int v){evert(u),access(v),splay(v),ch[v][0]=par[u]=0,updata(v);} int query(int now){access(now),splay(now);return siz[now];} int n,q; int main() { scanf("%d%d",&n,&q); for(int i=1;i<=n;i++) siz[i]=1; char op[3]; for(int u,v,i=1;i<=q;i++) { scanf("%s%d%d",op,&u,&v); if(op[0]=='Q') cat(u,v),printf("%lld\n",1ll*query(u)*query(v)),link(u,v); else link(u,v); } return 0; }
2018.12.7