BZOJ 3510: 首都 (lct)
阿新 • • 發佈:2018-11-29
hup 格式 如果 clas ++ root pushd tdi 異或
的距離,並且重心為根時的子樹大小均小於樹的大小\(/2\)。有了這幾個性質,那麽操作\(1\)就很簡單了,我們用啟發式合並,連接時\(dfs\) \(siz\)較小的子樹,然後每次\(link\)較小的子樹的每個節點和它的\(father\)。\(link\)裏處理重心,處理重心時,就先\(makeroot\)一下\(siz\)較大子樹的根節點,然後\(access\)一下新加入的點。這樣就將根節點到新加入節點的路徑找見了,也就是確定了一下移動方向。然後在找一下根節點的後繼,判斷能否移動。還要用並查集維護一下每棵樹的\(siz\)和根節點。
題面
Description
在X星球上有N個國家,每個國家占據著X星球的一座城市。由於國家之間是敵對關系,所以不同國家的兩個城市是不會有公路相連的。
X星球上戰亂頻發,如果A國打敗了B國,那麽B國將永遠從這個星球消失,而B國的國土也將歸A國管轄。A國國王為了加強統治,會在A國和B國之間修建一條公路,即選擇原A國的某個城市和B國某個城市,修建一條連接這兩座城市的公路。
同樣為了便於統治自己的國家,國家的首都會選在某個使得其他城市到它距離之和最小的城市,這裏的距離是指需要經過公路的條數,如果有多個這樣的城市,編號最小的將成為首都。
現在告訴你發生在X星球的戰事,需要你處理一些關於國家首都的信息,具體地,有如下3種信息需要處理:
1、A x y:表示某兩個國家發生戰亂,戰勝國選擇了x城市和y城市,在它們之間修建公路(保證其中城市一個在戰勝國另一個在戰敗國)。
2、Q x:詢問當前編號為x的城市所在國家的首都。
3、Xor:詢問當前所有國家首都編號的異或和。
Input
第一行是整數N,M,表示城市數和需要處理的信息數。
接下來每行是一個信息,格式如題目描述(A、Q、Xor中的某一種)。
Output
輸出包含若幹行,為處理Q和Xor信息的結果。
Sample Input
10 10
Xor
Q 1
A 10 1
A 1 4
Q 4
Q 10
A 7 6
Xor
Q 7
Xor
Sample Output
11
1
1
1
2
6
2
HINT
對於100%的數據,2<=N<=100000,1<=M<=200000。
解題思路
\(lct\)維護子樹信息。因為根據重心的性質,將兩棵樹拼起來,重心一定在這兩棵樹重心的連線上。還有一個性質就是當一棵樹增加一個葉節點時,重心最多向葉節點方向移動\(1\)
代碼
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> using namespace std; const int MAXN = 100005; 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,m,ch[MAXN][2],fa[MAXN],SIZ[MAXN]; int siz[MAXN],Siz[MAXN],Xor,F[MAXN],rt[MAXN]; int to[MAXN<<1],nxt[MAXN<<1],head[MAXN],cnt; bool rev[MAXN]; inline void add(int bg,int ed){ to[++cnt]=ed,nxt[cnt]=head[bg],head[bg]=cnt; } int Find(int x){ if(F[x]==x) return x; return F[x]=Find(F[x]); } inline bool isroot(int x){ return (x!=ch[fa[x]][0] && x!=ch[fa[x]][1]); } inline bool check(int x){ return (x==ch[fa[x]][1]); } inline void pushup(int x){ siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+Siz[x]+1; } 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]^=1; } } void pd(int x){ if(fa[x]) pd(fa[x]);pushdown(x); } 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(y) Siz[x]-=siz[y]; if(ch[x][1]) Siz[x]+=siz[ch[x][1]]; 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); fa[x]=y;Siz[y]+=siz[x];pushup(y);int zz=Find(y); makeroot(rt[zz]);access(x);splay(rt[zz]); int S=siz[rt[zz]],T=ch[rt[zz]][1];pushdown(T); while(ch[T][0]) T=ch[T][0],pushdown(T); access(T); if((Siz[T]+1)*2>S || (((Siz[T]+1)*2==S) && (T<rt[zz]))) { Xor^=rt[zz];Xor^=T;rt[zz]=T; } } void dfs(int x,int y){ ch[x][0]=ch[x][1]=fa[x]=rev[x]=0;Siz[x]=0;siz[x]=1; link(x,y);int u; for(int i=head[x];i;i=nxt[i]){ u=to[i];if(u==y) continue; dfs(u,x); } } int main(){ n=rd(),m=rd();char s[5];int x,y,u,v; for(int i=1;i<=n;i++) siz[i]=SIZ[i]=1,Xor^=i,F[i]=rt[i]=i; while(m--){ scanf("%s",s+1); if(s[1]==‘A‘) { x=rd(),y=rd(); u=Find(x);v=Find(y); if(SIZ[u]>SIZ[v]) swap(u,v),swap(x,y); F[u]=v;SIZ[v]+=SIZ[u];Xor^=rt[u]; dfs(x,y);add(x,y);add(y,x); } if(s[1]==‘Q‘) x=rd(),printf("%d\n",rt[Find(x)]); if(s[1]==‘X‘) printf("%d\n",Xor); } return 0; }
BZOJ 3510: 首都 (lct)