线段树合并,手打一遍过。
非常嗨皮,记录一下。
使用并查集,合并+查询。
代码如下:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int n,m,q,a[maxn],rev[maxn],f[maxn];
inline int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
inline char getc(){
char c=getchar();
while(c<'A'||c>'Z')c=getchar();
return c;
}
inline int find(int x){
if(f[x]==x)return x;
return f[x]=find(f[x]);
}
struct node{
int val,lc,rc;
}tr[maxn*20];
int cnt,rt[maxn];
inline int modify(int h,int l,int r,int x){
if(!h)h=++cnt;
tr[h].val++;
if(l==r)return h;
int mid=(l+r)>>1;
if(mid>=x)tr[h].lc=modify(tr[h].lc,l,mid,x);
else tr[h].rc=modify(tr[h].rc,mid+1,r,x);
return h;
}
inline int merge(int a,int b,int l,int r){
if(!a)return b;
if(!b)return a;
tr[a].val+=tr[b].val;
if(l==r)return a;
int mid=(l+r)>>1;
tr[a].lc=merge(tr[a].lc,tr[b].lc,l,mid);
tr[a].rc=merge(tr[a].rc,tr[b].rc,mid+1,r);
return a;
}
inline int query(int h,int l,int r,int x){
if(l==r)return l;
int mid=(l+r)>>1;
if(tr[tr[h].lc].val>=x)return query(tr[h].lc,l,mid,x);
else return query(tr[h].rc,mid+1,r,x-tr[tr[h].lc].val);
}
int main(){
n=read(),m=read();
for(int i=1;i<=n;i++)
f[i]=i,a[i]=read(),rev[a[i]]=i;
int x,y;
for(int i=1;i<=m;i++){
x=read(),y=read();
if(find(x)!=find(y))
f[find(x)]=find(y);
}
for(int i=1;i<=n;i++){
int t=find(i);
rt[t]=modify(rt[t],1,n,a[i]);
}
q=read();
char opt;
for(int i=1;i<=q;i++){
opt=getc(),x=read(),y=read();
if(opt=='Q')
if(tr[rt[find(x)]].val>=y)printf("%d
",rev[query(rt[find(x)],1,n,y)]);
else puts("-1");
else if(find(x)!=find(y)){
rt[find(x)]=merge(rt[find(x)],rt[find(y)],1,n);
f[find(y)]=find(x);
}
}
return 0;
}
深深地感到自己的弱小。