C68 线段树合并+并查集 P3224 [HNOI2012] 永无乡
视频链接:254 线段树合并+并查集 P3224 [HNOI2012] 永无乡_哔哩哔哩_bilibili
#include <iostream> #include <cstring> #include <algorithm> using namespace std; void read(int &l){ //快读 l=0; char c=getchar(); while(!isdigit(c))c=getchar(); while(isdigit(c))l=l*10+c-'0',c=getchar(); } const int N=100005; #define mid (l+r)/2 int n,m,q,f[N]; //f:并查集 int root[N],tot; //根节点,开点个数 int ls[N*20],rs[N*20],id[N*20],sum[N*20]; //id:节点编号,sum:重要度的出现次数之和 int find(int x){ //找根 return x==f[x]?x:f[x]=find(f[x]); } void pushup(int u){ //上传 sum[u]=sum[ls[u]]+sum[rs[u]]; } int change(int u,int l,int r,int p,int i){ //点修 if(!u) u=++tot; if(l==r){id[u]=i; sum[u]++; return u;} if(p<=mid) ls[u]=change(ls[u],l,mid,p,i); else rs[u]=change(rs[u],mid+1,r,p,i); pushup(u); return u; } int merge(int x,int y){ //合并 if(!x||!y) return x+y; ls[x]=merge(ls[x],ls[y]); rs[x]=merge(rs[x],rs[y]); pushup(x); return x; } int query(int u,int l,int r,int k){ //点查 if(l==r) return id[u]; int ans=0; if(k<=sum[ls[u]]) ans=query(ls[u],l,mid,k); else ans=query(rs[u],mid+1,r,k-sum[ls[u]]); return ans; } int main(){ read(n);read(m); int x,y; for(int i=1;i<=n;i++){ f[i]=i; read(x); root[i]=change(root[i],1,n,x,i); } for(int i=1;i<=m;i++){ read(x);read(y);x=find(x);y=find(y); if(x==y) continue; f[y]=x; root[x]=merge(root[x],root[y]); } read(q); while(q--){ char ch[2]; scanf("%s",ch); if(ch[0]=='B'){ read(x);read(y); x=find(x);y=find(y); if(x==y) continue; f[y]=x; root[x]=merge(root[x],root[y]); } else{ read(x);read(y); x=find(x); int ans=query(root[x],1,n,y); ans=ans?ans:-1; printf("%d\n",ans); } } }