P3224 [HNOI2012]永無鄉
題目描述
永無鄉包含 n 座島,編號從 1 到 n ,每座島都有自己的獨一無二的重要度,按照重要度可以將這 n 座島排名,名次用 1 到 n 來表示。某些島之間由巨大的橋連接,通過橋可以從一個島到達另一個島。如果從島 a 出發經過若幹座(含 0 座)橋可以 到達島 b ,則稱島 a 和島 b 是連通的。
現在有兩種操作:
B x y 表示在島 x 與島 y 之間修建一座新橋。
Q x k 表示詢問當前與島 x 連通的所有島中第 k 重要的是哪座島,即所有與島 x 連通的島中重要度排名第 k 小的島是哪座,請你輸出那個島的編號。
輸入輸出格式
輸入格式:第一行是用空格隔開的兩個正整數 n 和 m ,分別表示島的個數以及一開始存在的橋數。
接下來的一行是用空格隔開的 n 個數,依次描述從島 1 到島 n 的重要度排名。隨後的 m 行每行是用空格隔開的兩個正整數 ai 和 bi ,表示一開始就存在一座連接島 ai和島 bi的橋。
後面剩下的部分描述操作,該部分的第一行是一個正整數 q ,表示一共有 q 個操作,接下來的 q行依次描述每個操作,操作的 格式如上所述,以大寫字母 Q 或 B 開始,後面跟兩個不超過 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]永無鄉