【题解】
Treap 启发式合并:
初始时给每个点建一个treap,连边时启发式合并,将小的treap的每个结点插入大的treap中,并delete掉多余结点
【代码】
#include<stdio.h> #include<stdlib.h> int fa[100005],num[100005]; struct Node { Node* ch[2]; int v,r,s; int cmp_v(int x) const { if(x==v) return -1; if(x<v) return 0; return 1; } int cmp_s(int x) const { if( x == ch[0]->s + 1 ) return -1; if( x <= ch[0]->s ) return 0; return 1; } }; Node *root[100005],*null; int father(int x) { if(fa[x]!=x) fa[x]=father(fa[x]); return fa[x]; } void init(int n) { int i; null=new Node(); null->ch[0]=null->ch[1]=NULL; null->v=null->s=null->r=0; for(i=0;i<=n;i++) { root[i]=null; fa[i]=i; } } void wh(Node* &o) { o->s = o->ch[0]->s + o->ch[1]->s + 1; } void xz(Node* &o,int d) { Node* k=o->ch[d^1]; o->ch[d^1]=k->ch[d]; k->ch[d]=o; wh(o); wh(k); o=k; } void tj(Node* &o,int x) { int d=o->cmp_v(x); if(o==null) { o=new Node(); o->ch[0]=o->ch[1]=null; o->v=x; o->r=rand(); o->s=1; return; } o->s++; tj(o->ch[d],x); if( o->ch[d]->r < o->r ) xz(o,d^1); } void cr(Node* &x,Node* &y)//将x树插入y树 { if(x->ch[0]!=null) cr(x->ch[0],y); if(x->ch[1]!=null) cr(x->ch[1],y); tj(y,x->v); delete x;//释放空间 x=null; } void hb(int x,int y)//合并以root[x]为根的树和以root[y]为根的树,启发式合并 { if( root[x]->s < root[y]->s ) { fa[x]=y; cr(root[x],root[y]); } else { fa[y]=x; cr(root[y],root[x]); } } int cx(Node* &o,int k) { int d=o->cmp_s(k); if(d==-1) return o->v; if(d==1) k -= o->ch[0]->s + 1; return cx(o->ch[d],k); } int main() { srand(25); char s[5]; int n,m,q,i,x,y; scanf("%d%d",&n,&m); init(n); for(i=1;i<=n;i++) { scanf("%d",&x); num[x]=i; tj(root[i],x); } for(i=1;i<=m;i++) { scanf("%d%d",&x,&y); if(father(x)!=father(y)) hb(fa[x],fa[y]); } scanf("%d",&q); for(;q>0;q--) { scanf("%s%d%d",s,&x,&y); if(s[0]=='B') if(father(x)!=father(y)) hb(fa[x],fa[y]); if(s[0]=='Q') { if( root[father(x)]->s < y ) printf("-1\n"); else printf("%d\n",num[cx(root[fa[x]],y)]); } } return 0; }