要维护的是一个连通块的有序序列,每次查询第k个值的编号,用 splay 很容易实现。用splay维护一个pair(权值,编号),查询即查询排名为 k 的值。
初始的时候对开 n 个根节点,分别插入 n 个值。
当添加一座桥(或输入一座桥),两个不同联通块所在的splay 用启发式合并,把每个点都插入即可。维护连通块用并查集,只需要维护连通块的根节点所代表的splay树
由于使用启发式合并,每个点最多被插入 ,复杂度为 ,如果不回收结点编号,空间复杂度将达到 (回收结点编号莫名起码写挂了)
#include<bits/stdc++.h>
using namespace std;
#define pii pair<int,int>
#define fir first
#define sec second
const int maxn = 1e6 + 10;
const int inf = 0x3f3f3f3f;
int n,m,a[maxn],p[maxn],q;
char op[10];
vector<pii> tmp;
int find(int x) {
return p[x] == x ? x : p[x] = find(p[x]);
}
int smaller(pii a,pii b) {
if (a.fir != b.fir) return a.fir < b.fir;
if (a.sec != b.sec) return a.sec < b.sec;
}
struct Splay_tree {
int ch[maxn][2]; //ch[u][0] 表示 左二子,ch[u][1] 表示右儿子
int f[maxn]; //当前节点的父节点
int sz[maxn]; //当前节点的子树的节点个数
pii val[maxn]; //当前节点的权值和编号
int cnt[maxn]; //当前节点所表示的值的个数
int root[maxn]; //根节点
int tot; //总节点的个数
queue<int> q; //编号回收队列 ,防止空间复杂度达到 nlogn
inline bool get(int x){
return ch[f[x]][1]==x;
}
void init() {
tot = 0;
memset(root,0,sizeof root);
memset(f,0,sizeof f);
memset(sz,0,sizeof sz);
memset(cnt,0,sizeof cnt);
memset(ch,0,sizeof ch);
//f[0] = ch[0][0] = ch[0][1] = sz[0] = cnt[0] = 0;
//val[0] = pii(0,0);
}
void pushup(int rt) { //维护 rt 的 sz
if(rt) {
sz[rt] = cnt[rt];
if(ch[rt][0]) sz[rt] += sz[ch[rt][0]];
if(ch[rt][1]) sz[rt] += sz[ch[rt][1]];
}
}
void newnode(int rt,pii v,int fa) { //新建节点
f[rt] = fa;
val[rt] = v; cnt[rt] = sz[rt] = 1;
ch[rt][0] = ch[rt][1] = 0;
}
void delnode(int &rt) {
if(ch[rt][0]) delnode(ch[rt][0]);
if(ch[rt][1]) delnode(ch[rt][1]);
f[rt] = sz[rt] = cnt[rt] = 0;
val[rt] = pii(0,0);
ch[rt][0] = ch[rt][1] = 0;
//q.push(rt);
rt = 0;
}
void rotate(int x) { //旋转操作,根据 x 在 f[x] 的哪一侧进行左旋和右旋
int old = f[x], oldf = f[old];
int whichx = get(x);
ch[old][whichx] = ch[x][whichx ^ 1];
f[ch[old][whichx]] = old;
ch[x][whichx ^ 1] = old; f[old] = x;
f[x] = oldf;
if(oldf) ch[oldf][ch[oldf][1] == old] = x;
pushup(old); pushup(x); //不要忘记更新size
}
void splay(int &rt,int x,int goal) { //将 x 旋到 goal节点 下面
for (int fa = f[x]; fa != goal; rotate(x), fa = f[x]) //再把x翻上来
if (f[fa] != goal) //如果fa非根,且x 和 fa是同一侧,那么先翻转fa,否则先翻转x
rotate((get(x)==get(fa))?fa:x);
if (goal == 0)
rt = x;
}
int find(int rt,pii x) { //查找 x,若 x 不存在返回的是 x 的前驱或者后继 (不一定就是前驱或者后继,两者都可能)
int now = rt, father = 0;
if(!now) return now;
while(1) {
if(val[now].fir == x.fir) return now;
if(ch[now][0] && x.fir < val[now].fir) {
father = now;
now = ch[now][0];
} else if(ch[now][1] && x.fir > val[now].fir) {
father = now;
now = ch[now][1];
} else {
return now;
}
}
}
int findx(int rt,int x) { //查询第x小的节点
int now = rt;
if (!now || x > sz[rt]) return 0;
while(1) {
if(ch[now][0] && sz[ch[now][0]] >= x) {
now = ch[now][0];
} else {
int sum = cnt[now] + (ch[now][0] ? sz[ch[now][0]] : 0);
if (x <= sum) return now;
x -= sum, now = ch[now][1];
}
}
return now;
}
void insert(int &rt,pii x) { //把 x 插入到 splay中
int now = rt, father = 0,p = 0;
if(rt == 0) {
if (!q.empty()) p = q.front(), q.pop();
else p = ++tot;
newnode(p,x,0);
rt = p;
return ;
}
while(1) {
if(val[now].fir == x.fir) {
cnt[now] ++; sz[now]++;
pushup(now);
splay(rt,now,0);
break;
}
father = now;
now = ch[now][x.fir > val[now].fir];
if(!now) { //该节点不存在,则新建节点,并把这个节点旋转上去作为根节点
if (!q.empty()) p = q.front(), q.pop();
else p = ++tot;
newnode(p,x,father);
ch[father][x.fir > val[father].fir] = tot;
f[p] = father;
pushup(p); //pushup(father);
splay(rt,p,0);
break;
}
//printf("%d %d %d\n",rt,now,father);
}
}
void dfs(int rt) {
if(!rt) return ;
dfs(ch[rt][0]);
tmp.push_back(val[rt]);
dfs(ch[rt][1]);
}
}tree;
int main() {
//freopen("out.txt","w",stdout);
scanf("%d%d",&n,&m);
tree.init();
for (int i = 1; i <= n; i++) {
p[i] = i,scanf("%d",&a[i]);
tree.insert(tree.root[i],pii(a[i],i));
}
for (int i = 1,x,y; i <= m; i++) {
scanf("%d%d",&x,&y);
int fx = find(x);
int fy = find(y);
//printf("***%d %d %d %d\n",fx,fy,tree.sz[tree.root[fx]],tree.sz[tree.root[fy]]);
if(fx == fy) continue;
if(tree.sz[tree.root[fx]] < tree.sz[tree.root[fy]]) swap(fx,fy);
tree.dfs(tree.root[fy]);
tree.delnode(tree.root[fy]);
for (auto it : tmp)
tree.insert(tree.root[fx],it);
p[fy] = fx;
//printf("&&&%d %d %d %d %d\n",fx,fy,tree.sz[tree.root[fx]],tree.sz[tree.root[fy]]);
tmp.clear();
}
scanf("%d",&q);
while(q--) {
int x,y; scanf("%s%d%d",op,&x,&y);
if (op[0] == 'Q') {
int fx = find(x);
int res = tree.findx(tree.root[fx],y);
if (!res) puts("-1");
else printf("%d\n",tree.val[res].sec);
} else {
int fx = find(x), fy = find(y);
if (fx != fy) {
//printf("***%d %d %d %d\n",fx,fy,tree.sz[tree.root[fx]],tree.sz[tree.root[fy]]);
if(tree.sz[tree.root[fx]] < tree.sz[tree.root[fy]]) swap(fx,fy);
tree.dfs(tree.root[fy]);
tree.delnode(tree.root[fy]);
for (auto it : tmp)
tree.insert(tree.root[fx],it);
p[fy] = fx;
tmp.clear();
}
}
}
return 0;
}