用并查集维护集合关系,同时用线段树查询
出现合并时,将线段树合并,类似左偏树
http://www.lydsy.com/JudgeOnline/problem.php?id=2733
/************************************************************** Problem: 2733 User: 1349367067 Language: C++ Result: Accepted Time:2500 ms Memory:25884 kb ****************************************************************/ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define N 100011 using namespace std; int n,m; int ls[N*20],rs[N*20],size[N*20],num; int fa[N],No[N],c[N]; inline int findf(int x) { if (x==fa[x]) return x; else return fa[x]=findf(fa[x]); } void build(int x,int l,int r,int a) { if (l==r) { size[x]=1;return; } int mid=(l+r)/2; if (a<=mid) { num++;ls[x]=num; build(num,l,mid,a); } else { num++;rs[x]=num; build(num,mid+1,r,a); } size[x]=1; } int merge(int x,int y) { if (!x) return y; if (!y) return x; ls[x]=merge(ls[x],ls[y]); rs[x]=merge(rs[x],rs[y]); size[x]=size[ls[x]]+size[rs[x]]; return x; } int findx(int x,int l,int r,int a) { if (l==r) return l; int mid=(l+r)/2; if (a<=size[ls[x]]) return findx(ls[x],l,mid,a); else return findx(rs[x],mid+1,r,a-size[ls[x]]); } void init() { scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) scanf("%d",&c[i]); for (int i=1;i<=n;i++) No[c[i]]=i; num=n; for (int i=1;i<=n;i++) build(i,1,n,c[i]); for (int i=1;i<=n;i++) fa[i]=i; int l,r; for (int i=1;i<=m;i++) { scanf("%d%d",&l,&r); l=findf(l);r=findf(r); if (l==r) continue; if (l>r) swap(l,r); fa[r]=l; merge(l,r); } int Q; char ch[10]; scanf("%d",&Q); for (int i=1;i<=Q;i++) { scanf("%s",ch); if (ch[0]=='B') { scanf("%d%d",&l,&r); l=findf(l);r=findf(r); if (l==r) continue; if (l>r) swap(l,r); fa[r]=l; merge(l,r); } else { scanf("%d%d",&l,&r); l=findf(l); if (r>size[l]) printf("-1\n"); else printf("%d\n",No[findx(l,1,n,r)]); } } } int main() { init(); return 0; }