傳送門php
題目要求合併集合和查詢某個集合中的第\(k\)大,發現線段樹合併能夠作。c++
又有一個很是好的性質,一個權值對應惟一的一個位置,因此在權值線段樹上直接在相應權值打上標記,查詢的時候直接查詢到底,合併直接上線段樹合併,就能夠了。spa
#include <bits/stdc++.h> using namespace std; const int MAXN=1e5+7; #define mid ((l+r)>>1) int f[MAXN],st[MAXN<<5],L[MAXN<<5],R[MAXN<<5],T[MAXN],n,m,fa[MAXN<<5],sz,a[MAXN],q; char opt[2]; inline int read() { int x=0,c=1; char ch=' '; while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); while(ch=='-')c*=-1,ch=getchar(); while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar(); return x*c; } inline int find(int x) {return f[x]==x?f[x]:f[x]=find(f[x]);} inline int query(int x,int k) { if(st[x]<k) return -1; if(st[x]==k) return fa[x]; if(st[L[x]]<k) return query(R[x],k-st[L[x]]); else return query(L[x],k); } inline int query(int x,int l,int r,int k) { if(st[x]<k) return -1; if(l==r) return fa[x]; if(st[L[x]]<k) return query(R[x],mid+1,r,k-st[L[x]]); else return query(L[x],l,mid,k); } inline void modify(int &u,int l,int r,int k,int x) { if(!u) u=++sz; if(l==r){ st[u]++;fa[u]=x; return; } if(mid>=k) modify(L[u],l,mid,k,x); else modify(R[u],mid+1,r,k,x); st[u]=st[L[u]]+st[R[u]]; // if(!R[u]) fa[u]=fa[L[u]];else fa[u]=fa[R[u]]; } inline void merge(int &u,int v) { if(!u||!v){u+=v;return;} st[u]+=st[v]; merge(L[u],L[v]);merge(R[u],R[v]); } int main() { n=read();m=read(); for(int i=1;i<=n;i++) a[i]=read(),f[i]=i; for(int i=1;i<=n;i++) modify(T[i],1,n,a[i],i); for(int i=1;i<=m;i++){ int x=read(),y=read(); int r1=find(x),r2=find(y); if(r1==r2) continue; f[r2]=r1; merge(T[r1],T[r2]); } q=read(); while(q--){ scanf("%s",opt); int x=read(),y=read(); if(opt[0]=='B'){ int r1=find(x),r2=find(y); if(r1==r2) continue; f[r2]=r1; merge(T[r1],T[r2]); } else { int d=find(x); printf("%d\n",query(T[d],1,n,y)); } } }