在每个点建立值域线段树,连边时用并查集判断连通性,然后将两个连通块的祖先合并,最后查询时输出x所在连通块的祖先的信息就行了
#include<bits/stdc++.h>
using namespace std;
const int N = 5e5+7;
int fa[N],Rank[N],Island[N];
int Find(int x)
{
if(x==fa[x]) return x;
return fa[x]=Find(fa[x]);
}
int n,m,q;
inline int read()
{
int X=0; bool flag=1; char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') flag=0; ch=getchar();}
while(ch>='0'&&ch<='9') {X=(X<<1)+(X<<3)+ch-'0'; ch=getchar();}
if(flag) return X;
return ~(X-1);
}
int cnt[10*N],lson[10*N],rson[10*N],tot,rot[N];
void pushup(int k)
{
cnt[k]=cnt[lson[k]]+cnt[rson[k]];
}
void update(int &k,int l,int r,int x)
{
k=++tot;
if(l==r)
{
cnt[k]=1;
return;
}
int mid=(l+r)>>1;
if(x<=mid) update(lson[k],l,mid,x);
else update(rson[k],mid+1,r,x);
pushup(k);
}
void merge(int x,int y,int l,int r)
{
if(l==r) return;
int mid=(l+r)>>1;
if(lson[x]&&lson[y]) merge(lson[x],lson[y],l,mid);
else if(!lson[x]&&lson[y]) lson[x]=lson[y];
if(rson[x]&&rson[y]) merge(rson[x],rson[y],mid+1,r);
else if(!rson[x]&&rson[y]) rson[x]=rson[y];
pushup(x);
}
int query(int x,int l,int r,int k)
{
if(cnt[x]<k) return -1;
if(l==r) return l;
int ans=cnt[lson[x]];
int mid=(l+r)>>1;
if(ans>=k) return query(lson[x],l,mid,k);
else return query(rson[x],mid+1,r,k-ans);
}
int main()
{
n=read();
m=read();
for(int i=1;i<=n;i++)
{
Rank[i]=read();
Island[Rank[i]]=i;
update(rot[i],1,n,Rank[i]);
fa[i]=i;
}
for(int i=1;i<=m;i++)
{
int x,y;
x=read();
y=read();
int fx=Find(x),fy=Find(y);
if(fx==fy) continue;
fa[fy]=fx;
merge(rot[fx],rot[fy],1,n);
}
char opt[3];
q=read();
while(q--)
{
int x,y;
scanf("%s%d%d",opt,&x,&y);
if(opt[0]=='B')
{
int fx=Find(x);
int fy=Find(y);
if(fx==fy) continue;
fa[fy]=fx;
merge(rot[fx],rot[fy],1,n);
}
else
{
int root=Find(x);
int ans=query(rot[root],1,n,y);
if(ans==-1) printf("-1\n");
printf("%d\n",Island[ans]);
}
}
return 0;
}