题意:给出$N$个点,每个点有其排名$k_i$($k_i \in [1 , N]$且两两不同),$Q$次操作,操作为在两个点之间连一条边与查询某个点所在连通块内第$K$大排名的点的编号。$N \leq 10^5 , Q \leq 3 \times 10^5$。
查询第$K$大很多时候都用$Splay$,但是在这里显然线段树合并更好用
我们使用并查集维护每个点所在的连通块,线段树叶子节点记录当前排名对应点的编号,非叶子节点记录连通块中对应范围的排名的出现次数。对于第一个操作如果两个点不在同一连通块内就合并,否则什么都不做;对于询问操作在线段树上二分即可。复杂度$O(nlogn)$
1 #include<bits/stdc++.h> 2 #define mid ((l + r) >> 1) 3 //This code is written by Itst 4 using namespace std; 5 6 inline int read(){ 7 int a = 0; 8 bool f = 0; 9 char c = getchar(); 10 while(c != EOF && !isdigit(c)){ 11 if(c == '-') 12 f = 1; 13 c = getchar(); 14 } 15 while(c != EOF && isdigit(c)){ 16 a = (a << 3) + (a << 1) + (c ^ '0'); 17 c = getchar(); 18 } 19 return f ? -a : a; 20 } 21 22 const int MAXN = 100010; 23 struct node{ 24 int l , r , size , ind; 25 }Tree[MAXN * 30]; 26 int root[MAXN] , fa[MAXN] , N , M , Q , cntNode; 27 28 int find(int x){ 29 return x == fa[x] ? x : (fa[x] = find(fa[x])); 30 } 31 32 void insert(int& now , int l , int r , int tar , int ind){ 33 if(!now) 34 now = ++cntNode; 35 ++Tree[now].size; 36 if(l == r) 37 Tree[now].ind = ind; 38 else 39 if(mid >= tar) 40 insert(Tree[now].l , l , mid , tar , ind); 41 else 42 insert(Tree[now].r , mid + 1 , r , tar , ind); 43 } 44 45 int merge(int p , int q){ 46 if(!p) 47 return q; 48 if(!q) 49 return p; 50 Tree[p].size += Tree[q].size; 51 Tree[p].l = merge(Tree[p].l , Tree[q].l); 52 Tree[p].r = merge(Tree[p].r , Tree[q].r); 53 return p; 54 } 55 56 int find(int now , int l , int r , int rk){ 57 if(l == r) 58 return Tree[now].ind; 59 return Tree[Tree[now].l].size >= rk ? find(Tree[now].l , l , mid , rk) : find(Tree[now].r , mid + 1 , r , rk - Tree[Tree[now].l].size); 60 } 61 62 inline char getc(){ 63 char c = getchar(); 64 while(!isupper(c)) 65 c = getchar(); 66 return c; 67 } 68 69 int main(){ 70 #ifndef ONLINE_JUDGE 71 freopen("3224.in" , "r" , stdin); 72 //freopen("3224.out" , "w" , stdout); 73 #endif 74 N = read(); 75 M = read(); 76 for(int i = 1 ; i <= N ; ++i){ 77 fa[i] = i; 78 insert(root[i] , 1 , N , read() , i); 79 } 80 for(int i = 1 ; i <= M ; ++i){ 81 int a = find(read()) , b = find(read()); 82 if(a != b){ 83 fa[b] = a; 84 root[a] = merge(root[a] , root[b]); 85 } 86 } 87 for(Q = read() ; Q ; --Q) 88 if(getc() == 'Q'){ 89 int x = find(read()) , k = read(); 90 printf("%d\n" , Tree[root[x]].size < k ? -1 : find(root[x] , 1 , N , k)); 91 } 92 else{ 93 int a = find(read()) , b = find(read()); 94 if(a != b){ 95 fa[b] = a; 96 root[a] = merge(root[a] , root[b]); 97 } 98 } 99 return 0; 100 }