$ color{#0066ff}{ 题目描述 }$
永无乡包含 (n) 座岛,编号从 (1) 到 (n) ,每座岛都有自己的独一无二的重要度,按照重要度可以将这 (n) 座岛排名,名次用 (1) 到 (n) 来表示。某些岛之间由巨大的桥连接,通过桥可以从一个岛到达另一个岛。如果从岛 (a) 出发经过若干座(含 (0) 座)桥可以 到达岛 (b) ,则称岛 (a) 和岛 (b) 是连通的。
现在有两种操作:
B x y 表示在岛 (x) 与岛 (y) 之间修建一座新桥。
Q x k 表示询问当前与岛 (x) 连通的所有岛中第 (k) 重要的是哪座岛,即所有与岛 (x) 连通的岛中重要度排名第 (k) 小的岛是哪座,请你输出那个岛的编号。
(color{#0066ff}{输入格式})
第一行是用空格隔开的两个正整数 (n) 和 (m) ,分别表示岛的个数以及一开始存在的桥数。
接下来的一行是用空格隔开的 (n) 个数,依次描述从岛 (1) 到岛 (n) 的重要度排名。随后的 (m) 行每行是用空格隔开的两个正整数 (a_i) 和 (b_i) ,表示一开始就存在一座连接岛 (a_i) 和岛 (b_i) 的桥。
后面剩下的部分描述操作,该部分的第一行是一个正整数 (q) ,表示一共有 (q) 个操作,接下来的 (q) 行依次描述每个操作,操作的 格式如上所述,以大写字母 (Q) 或 (B) 开始,后面跟两个不超过 (n) 的正整数,字母与数字以及两个数字之间用空格隔开。
(color{#0066ff}{输出格式})
对于每个 Q x k 操作都要依次输出一行,其中包含一个整数,表示所询问岛屿的编号。如果该岛屿不存在,则输出(-1) 。
(color{#0066ff}{输入样例})
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
(color{#0066ff}{输出样例})
-1
2
5
1
2
(color{#0066ff}{数据范围与提示})
对于 20% 的数据 (n leq 1000, q leq 1000)
对于 100% 的数据 (n leq 100000, m leq n, q leq 300000)
(color{#0066ff}{题解})
B操作,平衡树暴力合并,因为最多(logn)次,所以没毛病
Q操作,Splay的kth就行
注意插入的时候要保证为根,先splay上去!
然而不splay上去也能A,数据水
#include<bits/stdc++.h>
#define LL long long
LL in() {
char ch; LL x = 0, f = 1;
while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
return x * f;
}
const int maxn = 3e5 + 10;
int n, m;
struct Splay {
protected:
struct node {
node *ch[2], *fa;
int val, siz;
node(int val = 0, int siz = 0): val(val), siz(siz) { fa = ch[0] = ch[1] = NULL; }
void upd() { siz = (ch[0]? ch[0]->siz : 0) + (ch[1]? ch[1]->siz : 0) + 1; }
int rk() { return ch[0]? ch[0]->siz + 1 : 1; }
bool isr() { return this == fa->ch[1]; }
void clr() {
siz = 1;
if(ch[0]) ch[0]->fa = NULL;
if(ch[1]) ch[1]->fa = NULL;
if(fa) fa->ch[val > fa->val] = NULL;
fa = ch[0] = ch[1] = NULL;
}
}pool[maxn];
void rot(node *x) {
node *y = x->fa, *z = y->fa;
bool k = x->isr(); node *w = x->ch[!k];
if(z) z->ch[y->isr()] = x;
(x->ch[!k] = y)->ch[k] = w;
(y->fa = x)->fa = z;
if(w) w->fa = y;
y->upd(), x->upd();
}
void splay(node *o) {
while(o->fa) {
if(o->fa->fa) rot(o->isr() ^ o->fa->isr()? o : o->fa);
rot(o);
}
}
int kth(node *o, int k) {
splay(o);
if(o->siz < k) return -1;
while(o && o->rk() != k) {
if(o->rk() > k) o = o->ch[0];
else k -= o->rk(), o = o->ch[1];
}
return o - pool;
}
void ins(node *rt, node *o) {
splay(rt);
o->clr();
node *now = rt, *fa = NULL;
while(now) fa = now, now = now->ch[o->val > now->val];
o->fa = fa;
fa->ch[o->val > fa->val] = o;
splay(o);
}
void dfs(node *o, node *rt) {
if(o->ch[0]) dfs(o->ch[0], rt);
if(o->ch[1]) dfs(o->ch[1], rt);
ins(rt, o);
}
node *findroot(node *o) { while(o->fa) o = o->fa; return o; }
void outtree(node *o) {
if(o->ch[0]) outtree(o->ch[0]);
if(o->ch[1]) outtree(o->ch[1]);
}
public:
void init(int *val, int n) { for(int i = 1; i <= n; i++) pool[i] = node(val[i], 1); }
void link(int x, int y) {
node *a = pool + x, *b = pool + y;
if(findroot(a) == findroot(b)) return;
splay(a), splay(b);
dfs(a, b);
}
int query(int x, int k) { return kth(pool + x, k); }
}s;
int val[maxn];
char getch() {
char ch;
while(!isalpha(ch = getchar()));
return ch;
}
int main() {
n = in(), m = in();
for(int i = 1; i <= n; i++) val[i] = in();
s.init(val, n);
int x, y;
for(int i = 1; i <= m; i++) x = in(), y = in(), s.link(x, y);
for(int T = in(); T --> 0;) {
if(getch() == 'Q') {
x = in(), y = in();
printf("%d
", s.query(x, y));
} else {
x = in(), y = in();
s.link(x, y);
}
}
return 0;
}