解题思路
题目相当于询问每个点所属集合的第(k)小的数的编号,查询某个数属于哪个集合可以用并查集来解决。题目还涉及了集合之间的合并,由于合并之后集合的元素会改变,所以需要动态询问第(k)小,可以用平衡树来解决。另外,在集合合并的时候需要用启发式合并,把小集合合并到大集合上,这样可以把时间复杂度降到(nlog^2n)的级别。
const int maxn = 1e5+10;
int n, m, a[maxn], p[maxn];
int find(int x) {
return p[x]==x ? p[x]:p[x]=find(p[x]);
}
int rt[maxn], idx;
struct Node {
int s[2], sz, v, p, num;
void init(int _v, int _num, int _p) {
v = _v, num = _num, p = _p;
sz = 1;
}
} tr[maxn*40];
inline void push_up(int u) {
tr[u].sz = tr[tr[u].s[0]].sz+tr[tr[u].s[1]].sz+1;
}
void rotate(int x) {
int y = tr[x].p, z = tr[y].p;
int k = tr[y].s[1]==x;
tr[z].s[tr[z].s[1]==y] = x, tr[x].p = z;
tr[y].s[k] = tr[x].s[k^1], tr[tr[x].s[k^1]].p = y;
tr[x].s[k^1] = y, tr[y].p = x;
push_up(y), push_up(x);
}
void splay(int &rt, int x, int k) {
while(tr[x].p!=k) {
int y = tr[x].p, z = tr[y].p;
if (z!=k)
if ((tr[y].s[1]==x)^(tr[z].s[1]==y)) rotate(x);
else rotate(y);
rotate(x);
}
if (!k) rt = x;
}
void insert(int &rt, int v, int num) {
int p = 0, u = rt;
while(u) p = u, u = tr[u].s[v>tr[u].v];
u = ++idx;
if (p) tr[p].s[v>tr[p].v] = u;
tr[u].init(v, num, p);
splay(rt, u, 0);
}
void merge(int u, int &rt) {
if (tr[u].v==INF || tr[u].v==-INF) return;
insert(rt, tr[u].v, tr[u].num);
if (tr[u].s[0]) merge(tr[u].s[0], rt);
if (tr[u].s[1]) merge(tr[u].s[1], rt);
}
int query(int u, int k) {
while(u) {
int sz = tr[tr[u].s[0]].sz;
if (sz>=k) u = tr[u].s[0];
else if (sz+1==k) return tr[u].num;
else k -= sz+1, u = tr[u].s[1];
}
return -1;
}
int main() {
IOS;
cin >> n >> m;
for (int i = 1; i<=n; ++i) cin >> a[i];
for (int i = 1; i<=n; ++i) p[i] = i;
while(m--) {
int a, b; cin >> a >> b;
p[find(a)] = find(b);
}
for (int i = 1; i<=n; ++i) {
int pi = find(i);
if (!rt[pi]) {
insert(rt[pi], -INF, i);
insert(rt[pi], INF, i);
}
insert(rt[pi], a[i], i);
}
int q; cin >> q;
while(q--) {
char op[10]; int a, b;
cin >> op >> a >> b;
if (op[0]=='B') {
int fa = find(a);
int fb = find(b);
if (fa!=fb) {
if (tr[rt[fa]].sz<=tr[rt[fb]].sz) {
p[fa] = fb;
merge(rt[fa], rt[fb]);
}
else {
p[fb] = fa;
merge(rt[fb], rt[fa]);
}
}
}
else {
int fa = find(a);
if (tr[rt[fa]].sz-2<b) cout << -1 << endl;
else cout << query(rt[fa], b+1) << endl;
}
}
return 0;
}