1. 程式人生 > >P3224 [HNOI2012]永無鄉

P3224 [HNOI2012]永無鄉

span 由於 一個 long %s div bottom mar %d

題目描述

永無鄉包含 n 座島,編號從 1n ,每座島都有自己的獨一無二的重要度,按照重要度可以將這 n 座島排名,名次用 1n 來表示。某些島之間由巨大的橋連接,通過橋可以從一個島到達另一個島。如果從島 a 出發經過若幹座(含 0 座)橋可以 到達島 b ,則稱島 a 和島 b 是連通的。

現在有兩種操作:

B x y 表示在島 x 與島 y 之間修建一座新橋。

Q x k 表示詢問當前與島 x 連通的所有島中第 k 重要的是哪座島,即所有與島 x 連通的島中重要度排名第 k 小的島是哪座,請你輸出那個島的編號。

輸入輸出格式

輸入格式:

第一行是用空格隔開的兩個正整數 nm ,分別表示島的個數以及一開始存在的橋數。

接下來的一行是用空格隔開的 n 個數,依次描述從島 1 到島 n 的重要度排名。隨後的 m 行每行是用空格隔開的兩個正整數 aibi ,表示一開始就存在一座連接島 ai和島 bi的橋。

後面剩下的部分描述操作,該部分的第一行是一個正整數 q ,表示一共有 q 個操作,接下來的 q行依次描述每個操作,操作的 格式如上所述,以大寫字母 QB 開始,後面跟兩個不超過 n 的正整數,字母與數字以及兩個數字之間用空格隔開。

輸出格式:

對於每個 Q x k 操作都要依次輸出一行,其中包含一個整數,表示所詢問島嶼的編號。如果該島嶼不存在,則輸出 −1

輸入輸出樣例

輸入樣例#1:
5  1
4  3 2 5 1
1  2
7
Q 3 2
Q 2 1
B 2 3
B 1 5
Q 2 1
Q 2 4
Q 2 3
輸出樣例#1:
-1
2
5
1
2

說明

對於 20% 的數據 n≤1000,q≤1000

對於 100% 的數據 n≤100000,m≤n,q≤300000

Solution:

  本題操作看完就是一眼題,Spaly碼農上線。

  初始時每個節點為一棵splay,然後對於兩點的聯系,由於各樹高均為$\log n$級別,所以直接暴力往上跳找到這兩點所在的splay的根節點,若不同就啟發式合並,把節點數較少的splay暴力插入到節點數多的那棵splay中。至於查詢就是裸的第k大值查詢了。

  時間復雜度$O(n\log n)$。

代碼:

/*Code by 520 -- 9.20*/
#include<bits/stdc++.h>
#define il inline
#define ll long long
#define RE register
#define For(i,a,b) for(RE int (i)=(a);(i)<=(b);(i)++)
#define Bor(i,a,b) for(RE int (i)=(b);(i)>=(a);(i)--)
#define son(x) (x==ch[fa[x]][1])
using namespace std;
const int N=500005;
int n,m,Q[N],tot;
int root[N],cnt,ch[N][2],fa[N],date[N],id[N],siz[N];

int gi(){
    int a=0;char x=getchar();
    while(x<0||x>9) x=getchar();
    while(x>=0&&x<=9) a=(a<<3)+(a<<1)+(x^48),x=getchar();
    return a;
}

il int newnode(int x){date[++cnt]=x;siz[cnt]=1;return cnt;}

il void pushup(int rt){siz[rt]=siz[ch[rt][0]]+siz[ch[rt][1]]+1;}

il void rotate(int x){
    int y=fa[x],z=fa[y],b=son(x),c=son(y),a=ch[x][!b];
    if(z) ch[z][c]=x; fa[x]=z;
    if(a) fa[a]=y; ch[y][b]=a;
    fa[y]=x,ch[x][!b]=y;
    pushup(y),pushup(x);
}

il void splay(int x,int i){
    while(fa[x]!=i) {
        int y=fa[x],z=fa[y];
        if(z==i) rotate(x),fa[x]=i;
        else {
            if(son(x)==son(y)) rotate(y),rotate(x);
            else rotate(x),rotate(x);
        }
    }
}

int getfa(int x){return !fa[x]?x:getfa(fa[x]);}

void insert(int &rt,int x){
    if(!rt) {rt=x,siz[x]=1;return;}
    if(date[x]<date[rt]) insert(ch[rt][0],x),fa[ch[rt][0]]=rt;
    else insert(ch[rt][1],x),fa[ch[rt][1]]=rt;
    pushup(rt);
}

int getrank(int rt,int k){
    if(siz[rt]<k) return -1;
    if(siz[ch[rt][0]]+1==k) return rt;
    if(siz[ch[rt][0]]+1>k) return getrank(ch[rt][0],k);
    else return getrank(ch[rt][1],k-siz[ch[rt][0]]-1);
}

void dfs(int x){
    if(!x) return ;
    dfs(ch[x][0]),Q[++tot]=x,dfs(ch[x][1]);
}

il void merge(int x,int y){
    x=getfa(x),y=getfa(y),tot=0;
    if(siz[x]>=siz[y]){
        dfs(y);For(i,1,tot) insert(x,Q[i]),splay(Q[i],0),x=Q[i];
    }
    else {
        dfs(x);For(i,1,tot) insert(y,Q[i]),splay(Q[i],0),y=Q[i];
    }
}

int main(){
    n=gi(),m=gi();
    int x,y;char s[3];
    For(i,1,n) x=gi(),root[i]=newnode(x);
    while(m--){
        x=gi(),y=gi();
        merge(x,y);
    }
    m=gi();
    while(m--){
        scanf("%s",s),x=gi(),y=gi();
        if(s[0]==Q) printf("%d\n",getrank(getfa(x),y));
        else {
            x=getfa(x),y=getfa(y);
            if(x!=y) merge(x,y);
        }
    }
    return 0;
}

P3224 [HNOI2012]永無鄉