Treap+启发式合并。依旧没什么需要用到脑子的。
#include <cstdlib> #include <cstdio> #include <algorithm> #include <iostream> #include <cctype> #include <cstring> #define rep(i, l, r) for(int i=l; i<=r; i++) #define clr(x, c) memset(x, c, sizeof(x)) #define maxn 100009 using namespace std; inline int read() { int x=0; char ch=getchar(); while (!isdigit(ch)) ch=getchar(); while (isdigit(ch)) x=x*10+ch-'0', ch=getchar(); return x; } int n=read(), m=read(); char q[5]; int h[maxn], l[maxn], r[maxn], s[maxn], k[maxn], pr[maxn]; inline void Init(){srand(2); rep(i, 1, n) s[i]=1, pr[i]=rand();} inline void update(int x){s[x]=s[l[x]]+s[r[x]]+1;} inline void Left(int v) { int u=r[v]; l[h[v]]==v ? l[h[v]]=u : r[h[v]]=u; h[u]=h[v]; r[v]=l[u], h[r[v]]=v; l[u]=v; h[v]=u; update(v), update(u); } inline void Right(int v) { int u=l[v]; l[h[v]]==v ? l[h[v]]=u : r[h[v]]=u; h[u]=h[v]; l[v]=r[u], h[l[v]]=v; r[u]=v, h[v]=u; update(v), update(u); } void Insert(int v, int u) { if (k[v] < k[u]) { if (!l[u]) {l[u]=v, h[v]=u; update(u); return;} Insert(v, l[u]); update(u); if (pr[l[u]] > pr[u]) Right(u); } else { if (!r[u]) {r[u]=v, h[v]=u, update(u); return;} Insert(v, r[u]); update(u); if (pr[r[u]] > pr[u]) Left(u); } } int Top(int v){return h[v]==0 ? v : Top(h[v]);} void Join(int v, int u) { if (v==u) return; if (s[v]>s[u]) swap(v, u); int a=l[v], b=r[v]; h[l[v]]=h[r[v]]=0, l[v]=r[v]=0, s[v]=1; Insert(v, u); if (a) Join(a, u); if (b) Join(b, u); } int Rank(int v, int k) { if (s[v]<k) return -1; while (s[l[v]]!=k-1) if (s[l[v]]>k-1) v=l[v]; else k-=s[l[v]]+1, v=r[v]; return v; } int main() { Init(); rep(i, 1, n) k[i]=read(); rep(i, 1, m) Join(Top(read()), Top(read())); int o=read(); rep(i, 1, o) { int x, y; scanf("%s%d%d", q, &x, &y); if (q[0]=='Q') printf("%d ", Rank(Top(x), y)); else Join(Top(x), Top(y)); } return 0; }