【Splay】【HNOI2012】永无乡

【题目描述】


基本上一次写过的平衡树,写篇题解留个纪念

开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));
		}
	}
}

猜你喜欢

转载自blog.csdn.net/Dy_Dream/article/details/84640711