【题目描述】
基本上一次写过的平衡树,写篇题解留个纪念
开n棵Splay维护这个联通块的第k小值,合并时用启发式合并,因为每次启发式合并一定是用小合并至大,所以每个点最多被合并log次,复杂度正确
维护合并情况采用并查集
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<stack>
#include<map>
#include<cstring>
#include<cmath>
using namespace std;
int n,m,q;
int root[100005],f[100005],sum[100005],tot,a[100005];
struct Tree
{
int v,id;
int fa;
int ch[2];
int recy,sum;
}tree[2000005];
int find(int x)
{
return (f[x]==x)?x:f[x]=find(f[x]);
}
int crepoint(int v,int fa,int id)
{
tot++;
tree[tot].id=id;
tree[tot].v=v;
tree[tot].recy=tree[tot].sum=1;
tree[tot].fa=fa;
return tot;
}
void push_up(int x)
{
tree[x].sum=tree[tree[x].ch[0]].sum+tree[tree[x].ch[1]].sum+tree[x].recy;
}
void connect(int x,int fa,int son)
{
tree[x].fa=fa;
tree[fa].ch[son]=x;
}
int whoson(int x)
{
return (tree[tree[x].fa].ch[0]==x)?0:1;
}
void rotate(int x)
{
int y=tree[x].fa;
int yson=whoson(x);
int mroot=tree[y].fa;
int mrootson=whoson(y);
int B=tree[x].ch[yson^1];
connect(B,y,yson);
connect(y,x,yson^1);
connect(x,mroot,mrootson);
push_up(y);
push_up(x);
}
void Splay(int x,int y,int nows)
{
while(tree[x].fa!=y)
{
rotate(x);
}
if(y==0) root[nows]=x;
}
int build(int now,int v,int id)
{
while(1)
{
tree[now].sum++;
int nex=(v<tree[now].v)?0:1;
if(!tree[now].ch[nex])
{
tree[now].ch[nex]=crepoint(v,now,id);
return tot;
}
now=tree[now].ch[nex];
}
}
int push(int now,int v,int id)
{
int add=build(root[now],v,id);
Splay(add,0,now);
}
void merge(int now,int x)
{
push(x,tree[now].v,tree[now].id);
if(tree[now].ch[0]) merge(tree[now].ch[0],x);
if(tree[now].ch[1]) merge(tree[now].ch[1],x);
}
int rank(int now,int x)
{
while(1)
{
if(tree[tree[now].ch[0]].sum>=x) now=tree[now].ch[0];
else if(tree[tree[now].ch[0]].sum<x&&tree[tree[now].ch[0]].sum+tree[now].recy>=x) return tree[now].id;
else x-=tree[tree[now].ch[0]].sum+tree[now].recy,now=tree[now].ch[1];
}
}
char op[1];
int main()
{
scanf("%d%d",&n,&m);
tot=n;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
root[i]=i,f[i]=i;
tree[i].recy=tree[i].sum=1;
tree[i].v=a[i];
tree[i].id=i;
sum[i]=1;
}
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
x=find(x),y=find(y);
if(x==y) continue;
if(sum[x]>=sum[y])
{
merge(root[y],x);
f[y]=x;
sum[x]+=sum[y];
}
else
{
merge(root[x],y);
f[x]=y;
sum[y]+=sum[x];
}
}
scanf("%d",&q);
for(int i=1;i<=q;i++)
{
scanf("%s",op);
int x,y;
scanf("%d%d",&x,&y);
if(op[0]=='B')
{
x=find(x),y=find(y);
if(x==y) continue;
if(sum[x]>=sum[y])
{
merge(root[y],x);
f[y]=x;
sum[x]+=sum[y];
}
else
{
merge(root[x],y);
f[x]=y;
sum[y]+=sum[x];
}
}
else
{
x=find(x);
if(y>sum[x])
{
printf("-1\n");
continue;
}
printf("%d\n",rank(root[x],y));
}
}
}