1. 程式人生 > >BZOJ 3510: 首都 (lct)

BZOJ 3510: 首都 (lct)

hup 格式 如果 clas ++ root pushd tdi 異或

題面

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\)

的距離,並且重心為根時的子樹大小均小於樹的大小\(/2\)。有了這幾個性質,那麽操作\(1\)就很簡單了,我們用啟發式合並,連接時\(dfs\) \(siz\)較小的子樹,然後每次\(link\)較小的子樹的每個節點和它的\(father\)\(link\)裏處理重心,處理重心時,就先\(makeroot\)一下\(siz\)較大子樹的根節點,然後\(access\)一下新加入的點。這樣就將根節點到新加入節點的路徑找見了,也就是確定了一下移動方向。然後在找一下根節點的後繼,判斷能否移動。還要用並查集維護一下每棵樹的\(siz\)和根節點。

代碼

#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)