传说中的启发式合并,就是选出n1logn2和n2logn1中的较小值(不要跟我提常数谢谢)
用平衡树维护一个联通块,我选的SBT(好高端的样子,煞笔树吗?),然后就是俩操作了:合并两棵树,查询一棵树内第k小的节点。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=100000+5;
inline int read(){
int x=0,f=1;char ch;
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int fa[N],pa[N],sz[N],lc[N],rc[N],key[N];
inline int find(int x){
return pa[x]!=x?pa[x]=find(pa[x]):x;
}
inline void pushup(int x){sz[x]=sz[lc[x]]+sz[rc[x]]+1;}
inline int findroot(int x){
while(fa[x])x=fa[x];
return x;
}
inline void lturn(int &x){
int k=rc[x];fa[lc[k]]=x;fa[k]=fa[x];fa[x]=k;rc[x]=lc[k];lc[k]=x;sz[k]=sz[x];pushup(x);x=k;
}
inline void rturn(int &x){
int k=lc[x];fa[rc[k]]=x;fa[k]=fa[x];fa[x]=k;lc[x]=rc[k];rc[k]=x;sz[k]=sz[x];pushup(x);x=k;
}
inline void maintain(int &x,bool flag){
if(!flag){
if(sz[lc[lc[x]]]>sz[rc[x]])rturn(x);
else if(sz[rc[lc[x]]]>sz[rc[x]]){
lturn(lc[x]);
rturn(x);
}else return;
}else{
if(sz[rc[rc[x]]]>sz[lc[x]])lturn(x);
else if(sz[lc[rc[x]]]>sz[lc[x]]){
rturn(rc[x]);
lturn(x);
}else return;
}
maintain(lc[x],false);maintain(rc[x],true);
maintain(x,true);maintain(x,false);
}
void ins(int &u,int v,int last){
if(!u){u=v;lc[u]=rc[u]=0;sz[u]=1;fa[u]=last;}
else{
sz[u]++;
if(key[v]<key[u])ins(lc[u],v,u);
else ins(rc[u],v,u);
maintain(u,key[v]>=key[u]);
}
}
void mergeto(int src,int &dest){
if(lc[src])mergeto(lc[src],dest);
if(rc[src])mergeto(rc[src],dest);
ins(dest,src,0);
}
void merge(int u,int v){
u=find(u);v=find(v);
if(u==v)return;
int rootu=findroot(u),rootv=findroot(v);
if(sz[rootu]<sz[rootv]){pa[u]=v;mergeto(rootu,rootv);}
else {pa[v]=u;mergeto(rootv,rootu);}
}
int kth(int u,int k){
int r=sz[lc[u]]+1;
if(r==k)return u;
else if(k<r)return kth(lc[u],k);
else return kth(rc[u],k-r);
}
int main(){
int n,m;n=read();m=read();
int u,v;
for(int i=1;i<=n;i++)pa[i]=i,key[i]=read(),sz[i]=1;
for(int i=1;i<=m;i++){
u=read();v=read();
merge(u,v);
}
int q=read();char opt[10];
while(q--){
scanf("%s%d%d",opt,&u,&v);
if(opt[0]=='B')merge(u,v);
else{
if(sz[findroot(u)]<v)printf("-1\n");
else printf("%d\n",kth(findroot(u),v));
}
}
return 0;
}