原题传送门
这个貌似叫
S
p
l
a
y
Splay
Splay
d
s
u
dsu
dsu
首先,这是个跟联通块有关的问题,所以需要用上并查集
然后,联通块的第k大当然是用
S
p
l
a
y
Splay
Splay维护了
可以对于每个点,都建一棵
S
p
l
a
y
Splay
Splay,对(1~n)点用并查集维护联通
点内用Splay维护
k
t
h
kth
kth
值得一提的是本题需要用到
S
p
l
a
y
Splay
Splay的合并,做法是将size小的splay一个点一个点插到size大的splay里面去
插入顺序则不用去管它,不需要中序遍历
注意:数组范围开大,我开了500010,因为不止有一棵 S p l a y Splay Splay
Code:
#include <bits/stdc++.h>
#define maxn 500010
using namespace std;
int sz, ff[maxn], rt[maxn], n, m, f[maxn];
int size[maxn], son[maxn][2], key[maxn], id[maxn];
inline int read(){
int s = 0, w = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
return s * w;
}
int get(int x){ return son[f[x]][1] == x; }
int getf(int k){ return k == ff[k] ? k : ff[k] = getf(ff[k]); }
void pushup(int x){
if (x > n){
size[x] = 1;
if (son[x][0] > n) size[x] += size[son[x][0]];
if (son[x][1] > n) size[x] += size[son[x][1]];
}
}
void connect(int x, int y, int z){
if (x > n) f[x] = y;
if (y > n) son[y][z] = x;
}
void rotate(int x){
int fa = f[x], ffa = f[fa], m = get(x), n = get(fa);
connect(son[x][m ^ 1], fa, m);
connect(fa, x, m ^ 1);
connect(x, ffa, n);
pushup(fa); pushup(x);
}
void splay(int x, int goal){
while (f[x] != goal){
int fa = f[x];
if (f[fa] != goal) rotate(get(x) == get(fa) ? fa : x);
rotate(x);
}
if (goal <= n) rt[goal] = x;
}
void insert(int x, int u){
int now = rt[u], fa = 0;
while (now && key[now] != x) fa = now, now = son[now][x > key[now]];
now = ++sz;
key[now] = x, size[now] = 1, son[now][0] = son[now][1] = 0;
f[now] = fa;
if (fa > n) son[fa][x > key[fa]] = now;
pushup(fa); splay(now, u);
}
void dfs(int now, int u){
if (son[now][0]) dfs(son[now][0], u);
if (son[now][1]) dfs(son[now][1], u);
insert(key[now], u);
}
void merge(int x, int y){
x = getf(x), y = getf(y);
if (x == y) return;
if (size[rt[x]] > size[rt[y]]) swap(x, y);
ff[x] = y;
dfs(rt[x], y);
}
int kth(int u, int x){
int now = rt[getf(u)];
if (size[now] < x) return -1;
while (1){
if (size[son[now][0]] >= x) now = son[now][0]; else
if (size[son[now][0]] + 1 >= x) return key[now]; else
x -= size[son[now][0]] + 1, now = son[now][1];
}
}
int main(){
n = read(), m = read(), sz = n << 1;
for (int i = 1; i <= n; ++i){
int x = read();
id[x] = i, rt[i] = n + i;
size[n + i] = 1, key[n + i] = x, f[n + i] = i, ff[i] = i;
son[n + i][0] = son[n + i][1] = 0;
}
for (int i = 1; i <= m; ++i){
int x= read(), y = read();
merge(x, y);
}
m = read();
while (m--){
char c = getchar();
for (; c != 'B' && c != 'Q'; c = getchar());
int x = read(), y = read();
if (c == 'B') merge(x, y); else{
int ans = kth(x, y);
printf("%d\n", ans == -1 ? -1 : id[ans]);
}
}
return 0;
}