/*
*
* 用并查集维护节点之间的连通关系,同一个连通块中的节点全部用
* 一个Splay实例维护,利用Splay来获取第k小数据
* 合并两个Splay的数据时候,注意小的树往大的树上合并
*
*/
#include <string.h>
#include <iostream>
#include <stdio.h>
#include <algorithm>
using namespace std;
class MergeSet {
private:
int __max_node_num;
int* __buf;
public:
MergeSet(int max_node_num) : __max_node_num(max_node_num) {
__buf = new int[__max_node_num+1];
memset(__buf, 0, sizeof(int) * (__max_node_num+1));
for (int node = 1; node <= max_node_num; node++) {
__buf[node] = node;
}
}
~MergeSet() {
delete[] __buf;
__buf = nullptr;
}
bool check_in_same_set(int a, int b) {
return __find(a) != 0 && __find(a) == __find(b);
}
void merge(int a, int b) {
__buf[__find(a)] = __find(b);
}
// 返回节点的最高层祖先编号
int get_root(int node) {
return __find(node);
}
private:
// 找x的祖先节点编号
int __find(int x) {
if (__buf[x] == x) {
return x;
}
__buf[x] = __find(__buf[x]);
return __buf[x];
}
};
#define MAX_SPLAY_NODE_NUM 2000000
struct Node {
int child[2]; // 左右子节点编号
int parent; // 父节点编号
int val; // 节点数值
int size; // 子树大小
int flag; // 懒标记
void init(int p, int v) {
child[0] = child[1] = 0;
parent = p;
val = v;
size = 1;
flag = 0;
}
} __splay_node_pool[MAX_SPLAY_NODE_NUM];
int __splay_pool_pos = 1;
class SplayTree {
private:
int __root; // 根节点编号
Node* __pool; // 对象池
int& __pool_pos; // 对象池最后一个分配位置
class __init_guard {
public:
__init_guard() {
__splay_node_pool[0].init(0, 0);
__splay_node_pool[0].size = 0;
}
};
static __init_guard __guard;
public:
SplayTree() : __pool_pos(__splay_pool_pos), __root(0), __pool(__splay_node_pool) {
}
// 翻转懒标记
void rev_flag(int idx) {
__pool[idx].flag ^= 1;
}
int get_left_child(int idx) {
return __pool[idx].child[0];
}
int get_right_child(int idx) {
return __pool[idx].child[1];
}
int get_root() {
return __root;
}
// 搬移函数,将编号为x的节点通过旋转搬移到k号节点的下面
void move(int x, int k) {
__move(x, k);
}
// 插入数值是val的节点
void insert(int val) {
int u = __root, p = 0;
while (u != 0) {
p = u;
u = __pool[u].child[val > __pool[u].val];
}
u = __pool_pos++;
if (p != 0) {
__pool[p].child[val > __pool[p].val] = u;
}
__pool[u].init(p, val);
while (p) {
__push_up(p);
p = __pool[p].parent;
}
__move(u, 0);
}
// 获取排名k的节点编号,返回0表示无解
int get_kth_idx(int k) {
int u = __root;
while (u) {
__push_down(u);
if (__pool[__pool[u].child[0]].size >= k) {
u = __pool[u].child[0];
} else if (__pool[__pool[u].child[0]].size + 1 == k) {
return u;
} else {
k -= __pool[__pool[u].child[0]].size + 1;
u = __pool[u].child[1];
}
}
return 0;
}
void get_mid_travel_list(int* ans) {
int pos = 0;
__get_mid_travel_list(__root, pos, ans);
}
// 返回第一个数值大于等于val的节点编号, 返回0无解
int lower_bound(int node, int val) {
if (node == 0) {
return 0;
}
if (val <= __pool[node].val) {
int idx = lower_bound(__pool[node].child[0], val);
if (idx != 0) {
return idx;
}
return node;
} else {
return lower_bound(__pool[node].child[1], val);
}
}
// 删除子树
void del_sub_tree(int node) {
Node& parent_node = __pool[__pool[node].parent];
int p = __pool[node].parent;
if (parent_node.child[0] == node) {
parent_node.child[0] = 0;
} else {
parent_node.child[1] = 0;
}
while (p) {
__push_up(p);
p = __pool[p].parent;
}
}
// 获取数值
int get_val(int idx) {
return __pool[idx].val;
}
// 获取树大小
int get_tree_size() {
return __pool[__root].size;
}
// 合并另外一个树所有节点,另外的树不变
void merge(SplayTree& other) {
__merge(other.__pool, other.__root);
}
private:
// 信息上传函数(即根据子节点信息更新序号是idx的节点的信息)
void __push_up(int idx) {
Node& node = __pool[idx];
node.size = 1 + __pool[node.child[0]].size + __pool[node.child[1]].size;
}
/******* 此处 __flag_oper __push_down_child_flag 两个函数的逻辑需要根据不同的问题场景进行修改 **********/
// 懒标记对应的操作,默认什么操作也没有,具体使用时候在此处添加操作
void __flag_oper(int idx) {
}
// 修改子节点的标记函数,默认就是将标记下传,不同问题可能有不同处理方式,这里把逻辑提出来
void __push_down_child_flag(int idx) {
}
// 懒标记下移操作
void __push_down(int idx) {
if (__pool[idx].flag) {
__flag_oper(idx);
__push_down_child_flag(idx);
__pool[idx].flag = 0;
}
}
// 统一的左旋和右旋函数,将编号为x对应的节点网上一层旋转
void __rotate(int x) {
int y = __pool[x].parent, z = __pool[y].parent;
int k1 = __pool[y].child[1] == x, k2 = __pool[z].child[1] == y;
__pool[z].child[k2] = x;
__pool[x].parent = z;
__pool[y].child[k1] = __pool[x].child[k1^1];
__pool[__pool[x].child[k1^1]].parent = y;
__pool[x].child[k1^1] = y;
__pool[y].parent = x;
__push_up(y);
__push_up(x);
}
// 搬移函数,将编号为x的节点通过旋转搬移到k号节点的下面
// k = 0 表示将x节点搬移到根节点位置
void __move(int x, int k) {
while (__pool[x].parent != k) {
int y = __pool[x].parent, z = __pool[y].parent;
if (z != k) {
if ( (__pool[y].child[1] == x) != (__pool[z].child[1] == y) ) {
__rotate(x);
} else {
__rotate(y);
}
}
__rotate(x);
}
if (k == 0) {
__root = x;
}
}
void __get_mid_travel_list(int cur, int& pos, int* ans) {
if (cur == 0) {
return;
}
__push_down(cur);
__get_mid_travel_list(__pool[cur].child[0], pos, ans);
ans[pos++] = __pool[cur].val;
__get_mid_travel_list(__pool[cur].child[1], pos, ans);
}
// 合并另外一棵树的子树的所有节点
void __merge(Node* pool, int node) {
if (node == 0) {
return;
}
insert(pool[node].val);
__merge(pool, pool[node].child[0]);
__merge(pool, pool[node].child[1]);
}
};
SplayTree::__init_guard SplayTree::__guard;
int node2imp[300005]; // 节点到重要度映射
int imp2node[300005]; // 重要度到节点映射
SplayTree* tree_ptr_buf[300005];
void build_bridge(MergeSet& merge_set, int a, int b) {
int imp_a = node2imp[a], imp_b = node2imp[b];
if (!merge_set.check_in_same_set(imp_a, imp_b)) {
int size_a = tree_ptr_buf[merge_set.get_root(imp_a)]->get_tree_size();
int size_b = tree_ptr_buf[merge_set.get_root(imp_b)]->get_tree_size();
if (size_a < size_b) {
tree_ptr_buf[merge_set.get_root(imp_b)]->merge(*tree_ptr_buf[merge_set.get_root(imp_a)]);
merge_set.merge(imp_a, imp_b);
} else {
tree_ptr_buf[merge_set.get_root(imp_a)]->merge(*tree_ptr_buf[merge_set.get_root(imp_b)]);
merge_set.merge(imp_b, imp_a);
}
}
}
int main() {
//freopen("/Users/grh/Programming/CLionProjects/Test/data.txt", "r", stdin);
int n, m, imp;
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%d", &imp);
imp2node[imp] = i;
node2imp[i] = imp;
tree_ptr_buf[imp] = new SplayTree();
tree_ptr_buf[imp]->insert(imp);
}
int a, b;
MergeSet merge_set(n);
for (int i = 0; i < m; i++) {
scanf("%d %d", &a, &b);
if (! (a >= 1 and b >= 1 and a <= n and b <= n) ) {
continue;
}
build_bridge(merge_set, a, b);
}
int cmd_num;
char cmd[2];
scanf("%d", &cmd_num);
for (int i = 0; i < cmd_num; i++) {
scanf("%s %d %d", cmd, &a, &b);
if (cmd[0] == 'B') {
if (! (a >= 1 and b >= 1 and a <= n and b <= n) ) {
continue;
}
build_bridge(merge_set, a, b);
} else {
imp = node2imp[a];
int idx = tree_ptr_buf[merge_set.get_root(imp)]->get_kth_idx(b);
if (idx != 0) {
imp = tree_ptr_buf[merge_set.get_root(imp)]->get_val(idx);
printf("%d\n", imp2node[imp]);
} else {
printf("-1\n");
}
}
}
for (int i = 1; i <= n; i++) {
delete tree_ptr_buf[i];
tree_ptr_buf[i] = nullptr;
}
return 0;
}