2733: [HNOI2012]永無鄉
Time Limit: 10 Sec Memory Limit: 128 MBDescription
永無鄉包含 n 座島,編號從 1 到 n,每座島都有自己的獨一無二的重要度,按照重要度可 以將這 n 座島排名,名次用 1 到 n 來表示。某些島之間由巨大的橋連接,通過橋可以從一個島 到達另一個島。如果從島 a 出發經過若干座(含 0 座)橋可以到達島 b,則稱島 a 和島 b 是連 通的。現在有兩種操作:B x y 表示在島 x 與島 y 之間修建一座新橋。Q x k 表示詢問當前與島 x連通的所有島中第 k 重要的是哪座島,即所有與島 x 連通的島中重要度排名第 k 小的島是哪 座,請你輸出那個島的編號。
Input
輸入文件第一行是用空格隔開的兩個正整數 n 和 m,分別 表示島的個數以及一開始存在的橋數。接下來的一行是用空格隔開的 n 個數,依次描述從島 1 到島 n 的重要度排名。隨后的 m 行每行是用空格隔開的兩個正整數 ai 和 bi,表示一開始就存 在一座連接島 ai 和島 bi 的橋。后面剩下的部分描述操作,該部分的第一行是一個正整數 q, 表示一共有 q 個操作,接下來的 q 行依次描述每個操作,操作的格式如上所述,以大寫字母 Q 或B 開始,后面跟兩個不超過 n 的正整數,字母與數字以及兩個數字之間用空格隔開。 對於 20%的數據 n≤1000,q≤1000
對於 100%的數據 n≤100000,m≤n,q≤300000
Output
對於每個 Q x k 操作都要依次輸出一行,其中包含一個整數,表 示所詢問島嶼的編號。如果該島嶼不存在,則輸出-1。
Sample Input
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
Sample Output
2
5
1
2
HINT
並查集維護一下連通性,對於每個連通塊建一顆權值線段樹,然后搞線段樹合並。
#include<cstdio> #include<iostream> using namespace std; #define N 100010 #define M 1800100 inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int fa[N]; int findf(int x){return x==fa[x]?x:fa[x]=findf(fa[x]);} int rt[N],ls[M],rs[M],sum[M],cnt; void add(int l,int r,int &y,int v) { if(!y) y=++cnt; if(l==r){sum[y]=1;return;} int mid=(l+r)>>1; if(v>mid) add(mid+1,r,rs[y],v); else add(l,mid,ls[y],v); sum[y]=sum[ls[y]]+sum[rs[y]]; } int que(int l,int r,int y,int k) { if(l==r) return l; int mid=(l+r)>>1; if(sum[ls[y]]>=k) return que(l,mid,ls[y],k); else return que(mid+1,r,rs[y],k-sum[ls[y]]); } int lj(int x,int y) { if(!x) return y; if(!y) return x; ls[x]=lj(ls[x],ls[y]); rs[x]=lj(rs[x],rs[y]); sum[x]=sum[ls[x]]+sum[rs[x]]; return x; } int n,m,a,b,q,v[N],di[N],x,k,ans; char cc; int main() { n=read();m=read(); for(int i=1;i<=n;i++) v[i]=read(); for(int i=0;i<=n;i++) fa[i]=i; for(int i=0;i<m;i++) { a=read();b=read(); a=findf(a);b=findf(b); fa[a]=b; } for(int i=1;i<=n;i++) { add(1,n,rt[findf(i)],v[i]); di[v[i]]=i; } q=read(); while(q--) { cc=getchar(); while(cc<'A'||cc>'Z') cc=getchar(); x=read();k=read(); if(cc=='Q') { a=findf(x); if(sum[rt[a]]<k){puts("-1");continue;} ans=que(1,n,rt[a],k); printf("%d\n",di[ans]); } else { a=findf(x);b=findf(k); if(a!=b) { fa[a]=b; rt[b]=lj(rt[a],rt[b]); } } } }