题解 P3224 【[HNOI2012]永无乡】
看到题解里面一堆权值线段树。。。
不行我要告诉自己这是一道平衡树的题!
于是我就是要写平衡树!
然而又一看题解
竟然没有用fhq Treap做的
于是赶紧来上一发
思路:
fhq Treap加启发式合并,每次把小树节点拆下来加到大树上
但是其实不用新建节点,也不用写队列,直接把son清空即可,然后再加进去
代码:
//by 减维
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<map>
#include<bitset>
#include<algorithm>
#define ll long long
#define maxn 100005
using namespace std;
int n,m,asd,cnt,rt[maxn],sz[maxn],siz[maxn],son[maxn][2],pri[maxn],val[maxn],ys[maxn];
int find(int x)
{
if(rt[x]==x)return x;
rt[x]=find(rt[x]);
return rt[x];
}
void upda(int x)
{
siz[x]=siz[son[x][0]]+siz[son[x][1]]+1;
}
void spli(int now,int k,int &x,int &y)
{
if(!now)x=y=0;
else{
if(val[now]<=k)
x=now,spli(son[now][1],k,son[now][1],y);
else
y=now,spli(son[now][0],k,x,son[now][0]);
upda(now);
}
}
int merge(int x,int y)
{
if(!x||!y)return x+y;
if(pri[x]<pri[y])
{
son[x][1]=merge(son[x][1],y);
upda(x);
return x;
}else{
son[y][0]=merge(x,son[y][0]);
upda(y);
return y;
}
}
void insert(int &root,int x)
{
int a,b;
int v=val[x];
spli(root,v,a,b);
root=merge(merge(a,x),b);
}
void dfs(int x,int &y)
{
if(!x)return ;
dfs(son[x][0],y);
dfs(son[x][1],y);
son[x][0]=son[x][1]=0;
insert(y,x);
}
int hebing(int x,int y)
{
if(siz[x]>siz[y])swap(x,y);
dfs(x,y);
return y;
}
int kth(int now,int k)
{
while(1)
{
if(k<=siz[son[now][0]])
now=son[now][0];
else if(k==siz[son[now][0]]+1)
return now;
else
k-=siz[son[now][0]]+1,now=son[now][1];
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)scanf("%d",&val[i]),rt[i]=i,pri[i]=rand(),siz[i]=sz[i]=1,ys[val[i]]=i;
cnt=n;
for(int i=1,a,b,c;i<=m;++i)
{
scanf("%d%d",&a,&b);
if(find(a)==find(b))continue;
c=hebing(rt[a],rt[b]);
rt[find(a)]=rt[find(b)]=c;
rt[c]=c;
}
scanf("%d",&asd);
char ch[5];
for(int i=1,a,b,c;i<=asd;++i)
{
scanf("%s%d%d",ch,&a,&b);
if(ch[0]=='B'){
if(find(a)==find(b))continue;
c=hebing(rt[a],rt[b]);
rt[find(a)]=rt[find(b)]=c;
rt[c]=c;
}else{
if(siz[find(a)]<b){
printf("-1\n");
continue;
}
printf("%d\n",ys[val[kth(find(a),b)]]);
}
}
return 0;
}