题目
思路
思路很好想,FHQtreap+启发式合并,但就是……恶心的代码,因为合并需要把所有拆出来再和在中间……
code:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<iostream>
#include<cstdlib>
using namespace std;
inline int read()
{
int ret,c,f=1;
while (((c=getchar())> '9'||c< '0')&&c!='-');
if (c=='-') f=-1,ret=0;
else ret=c-'0';
while ((c=getchar())>='0'&&c<='9') ret=ret*10+c-'0';
return ret*f;
}
struct f{
int val,key,l,r,siz;//真值,权值,左右儿子,父亲,子树大小,特殊标记这里指翻转
} tree[100006];
int cnt,n,m,root,x1,x2,x3,x4,x,z;
int id[100006],rt[100006];
int find(int x)
{
if (rt[x]==x) return x;
return rt[x]=find(rt[x]);
}
int New(int x)//建新点,传真值
{
tree[++cnt].val=x;
tree[cnt].siz=1;
tree[cnt].l=tree[cnt].r=0;
tree[cnt].key=rand();
id[x]=cnt;
return cnt;
}
void up(int id)//上传
{
tree[id].siz=tree[tree[id].l].siz+tree[tree[id].r].siz+1;
return;
}
void split(int id,int siz,int &l,int &r)//分裂,把从1开始大小<=siz的部分拆出来
{
if (id==0)
{
l=r=0;
return;
}
if (siz>=tree[id].val)//递归左儿子
{
l=id;
split(tree[id].r,siz,tree[id].r,r);
}
else//递归右儿子
{
r=id;
split(tree[id].l,siz,l,tree[id].l);
}
up(id);
return;
}
int merge(int l,int r)//合并,传入根节点编号
{
if (l==0||r==0)
{
return l+r;
}
if (tree[l].key<tree[r].key)//维护小根堆性质
{
tree[l].r=merge(tree[l].r,r);
up(l);
return l;
}
else
{
tree[r].l=merge(l,tree[r].l);
up(r);
return r;
}
}
void ins(int &y,int x)
{
int l=0,r=0;
split(y,tree[x].val,l,r);
y=merge(merge(l,x),r);
return;
}
void kc(int x,int &y)
{
if (x==0) return;
kc(tree[x].l,y);
kc(tree[x].r,y);
tree[x].l=tree[x].r=0;
ins(y,x);
return;
}
int mergee(int l,int r)
{
if (tree[l].siz>tree[r].siz) swap(l,r);
kc(l,r);
return r;
}
int GV(int id,int rak)//求值
{
while (1)
{
if (rak<=tree[tree[id].l].siz) id=tree[id].l;
else if (rak==tree[tree[id].l].siz+1) return tree[id].val;
else rak-=tree[tree[id].l].siz+1,id=tree[id].r;
}
}
int main()
{
srand(114514);
n=read(),m=read();
for (int i=1;i<=n;i++)
{
rt[i]=i;
New(read());
}
for (int i=1;i<=m;i++)
{
x=read(),x1=read();
if (find(x)==find(x1)) continue;
root=mergee(rt[x],rt[x1]);
rt[find(x)]=rt[find(x1)]=root;
rt[root]=root;
}
int q=read();
while (q--)
{
char opt;
cin>>opt;
x=read(),x1=read();
if (opt=='B')
{
if (find(x)==find(x1)) continue;
root=mergee(rt[x],rt[x1]);
rt[find(x)]=rt[find(x1)]=root;
rt[root]=root;
}
if (opt=='Q')
{
x2=find(x);
if (tree[x2].siz<x1) cout<<"-1\n";
else cout<<id[GV(x2,x1)]<<endl;
}
}
return 0;
}