其实很裸,用并查集维护每个点的信息已经别合并到哪个线段树里面了,然后权值线段树查第k大就行。
我一开始和naive地没用并查集,然后发现rt没有传递性。
写着写着反应过来,,其实一开始也可以这么写,,用rt当并查集用就行,,我感觉更naive了。
#include<bits/stdc++.h>
using namespace std;
#define in read()
int in{
int cnt=0,f=1;char ch=0;
while(!isdigit(ch)){
ch=getchar();if(ch=='-')f=-1;
}
while(isdigit(ch)){
cnt=cnt*10+ch-48;
ch=getchar();
}return cnt*f;
}
int n,m,Rank[100003],rt[100003];
struct node{
int l,r,size;
}t[3000003];int tot;
void modify(int &u,int l,int r,int key){
if(!u)u=++tot;
int mid=(l+r)>>1;t[u].size+=1;if(l==r)return;
if(key<=mid)modify(t[u].l,l,mid,key);
else modify(t[u].r,mid+1,r,key);
}
int merge(int u,int v){
if(!u||!v)return u+v;
t[u].size+=t[v].size;
t[u].l=merge(t[u].l,t[v].l);
t[u].r=merge(t[u].r,t[v].r);
return u;
}int belong[100003];
int query(int u,int l,int r,int k){
if(l==r){
return l;
}
int mid=(l+r)>>1,ls=t[t[u].l].size;
if(k<=ls)return query(t[u].l,l,mid,k);
else return query(t[u].r,mid+1,r,k-ls);
}
void debug(int u,int l,int r){
cout<<u<<" "<<l<<" "<<r<<" "<<t[u].size<<endl;int mid=(l+r)>>1;
if(t[u].l)debug(t[u].l,l,mid);if(t[u].r)debug(t[u].r,mid+1,r);
}int fa[100003];
int find(int x){
if(x==fa[x])return x;
return fa[x]=find(fa[x]);
}
signed main(){
n=in;m=in;tot=n;for(int i=1;i<=n;i++)Rank[i]=in,belong[Rank[i]]=i;
for(int i=1;i<=n;i++)fa[i]=i;//belong[n+1]=-1;
for(int i=1;i<=m;i++){
int a=in;int b=in;int x=find(a),y=find(b);fa[x]=y;//rt[x]=rt[y];
}int q=in;
for(int i=1;i<=n;i++){
modify(rt[find(i)],1,n,Rank[i]);
}char ch[3];int x,y;
while(q--){
scanf("%s",ch);x=in;y=in;
if(ch[0]=='B'){
int a=find(x),b=find(y);
if(rt[a]==rt[b])continue;//cout<<"X segment "<<endl;
//debug(rt[x],1,n);cout<<"Y segment"<<endl;debug(rt[y],1,n);
rt[a]=merge(rt[a],rt[b]);//rt[b]=rt[a];//cout<<"after segment "<<endl;
//debug(rt[x],1,n);
fa[b]=a;
}else{
x=find(x);
if(y>t[rt[x]].size){cout<<"-1"<<'\n';continue;}
int gu=query(rt[x],1,n,y);//cout<<"gu "<<gu<<" ";
cout<<belong[gu]<<'\n';
}
}
return 0;
}