用并查集维护联通块。
用线段树的合并来合并联通块。
自己YY了一个写法。
#include <map> #include <cmath> #include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define F(i,j,k) for (int i=j;i<=k;++i) #define D(i,j,k) for (int i=j;i>=k;--i) #define ll long long #define mp make_pair #define maxn 150005 int ls[maxn<<5],rs[maxn<<5],rt[maxn]; int fa[maxn],n,m,tot,sum[maxn<<5],q; char opt[11]; void modify(int o1,int &o2,int l,int r,int x,int f) { o2=++tot;sum[o2]=sum[o1]+f;if(l==r)return;int mid=l+r>>1; if (x<=mid) rs[o2]=rs[o1],modify(ls[o1],ls[o2],l,mid,x,f); else ls[o2]=ls[o1],modify(rs[o1],rs[o2],mid+1,r,x,f); } int gf(int k) { if (fa[k]==k) return k; else return fa[k]=gf(fa[k]); } int merge(int o1,int o2,int l,int r) { if (!(o1*o2)) return o1+o2; int mid=l+r>>1;sum[o1]+=sum[o2]; ls[o1]=merge(ls[o1],ls[o2],l,mid); rs[o1]=merge(rs[o1],rs[o2],mid+1,r); return o1; } int query(int o,int l,int r,int x) { if (sum[o]<x) return -1; if (l==r) return l; int mid=l+r>>1; if (x<=sum[ls[o]]) return query(ls[o],l,mid,x); else return query(rs[o],mid+1,r,x-sum[ls[o]]); } void Debug(int o,int l,int r) { if (!o) return ; printf(" %d %d == %d ",l,r,sum[o]); if (l==r) return ; Debug(ls[o],l,l+r>>1); Debug(rs[o],(l+r>>1)+1,r); } int list[maxn]; int main() { scanf("%d%d",&n,&m); F(i,1,n) fa[i]=i,rt[i]=0; F(i,1,n) { int x; scanf("%d",&x); modify(rt[i],rt[i],1,n,x,1); list[x]=i; } F(i,1,m) { int x,y,fx,fy; scanf("%d%d",&x,&y); fx=gf(x);fy=gf(y); if (fx==fy) continue; else fa[fy]=fx,rt[fx]=merge(rt[fx],rt[fy],1,n); } scanf("%d",&q); F(i,1,q) { int x,y,fx,fy,tmp; scanf("%s%d%d",opt,&x,&y); switch(opt[0]) { case 'Q': fx=gf(x); tmp=query(rt[fx],1,n,y); printf("%d ",tmp==-1?-1:list[query(rt[fx],1,n,y)]); break; case 'B': fx=gf(x);fy=gf(y); if (fx!=fy) { fa[fy]=fx; rt[fx]=merge(rt[fx],rt[fy],1,n); } break; } } }