【題解】
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;
}