左偏树

左偏树,可并堆的一种,满足根节点优先级最小(最大),各结点优先级递增(递减)

定义左偏树的外界点为左子树或者右子树为空的结点。定义结点的距离为此结点到最近外界点的所经过的边数。 

左偏树满足左偏性质,任意结点的左子结点的距离不小于右子结点的距离。

由左偏性质得:一结点的距离=0或(右子结点距离+1)

合并:将两子树中根较大(小)的树的根作为根节点,令其右子树与另外一棵树合并。

    合并完成后比较左右两子结点的距离,确保左子结点距离大于等于右子结点距离。

插入:将新结点与原有树合并

删除:将根节点提出,合并其左右子树

合并代码如下:

int merge(int x,int y)
{
	if(x==0)return y;
	if(y==0)return x;
	if(val[x]<val[y])swap(x,y);
	ch[x][1]=merge(ch[x][1],y);
	if(dis[ch[x][0]]<dis[ch[x][1]])swap(ch[x][0],ch[x][1]);
	if(!ch[x][1])   dis[x]=0;
	else			dis[x]=dis[ch[x][1]]+1;
	return x;
}
以下为猴王的代码:

题目:http://fzoj.xndxfz.com/JudgeOnline/problem.php?id=1636

#include<stdio.h>
#include<algorithm>
using namespace std;
const int MAX=1e5+5;
int inline read()
{
	int h,f=1;char ch;
	while((ch=getchar())>'9'||ch<'0')
	if(ch=='-')f=-1;h=ch-'0';
	while((ch=getchar())>='0'&&ch<='9')
	h=h*10+ch-'0';return h*f;
}
int fa[MAX],ch[MAX][2],val[MAX],dis[MAX];
int merge(int x,int y)
{
	if(x==0)return y;
	if(y==0)return x;
	if(val[x]<val[y])swap(x,y);
	ch[x][1]=merge(ch[x][1],y);
	if(dis[ch[x][0]]<dis[ch[x][1]])swap(ch[x][0],ch[x][1]);
	if(!ch[x][1])   dis[x]=0;
	else			dis[x]=dis[ch[x][1]]+1;
	return x;
}
int father(int n)
{
	return (fa[n]==n)?n:fa[n]=father(fa[n]);
}
int fight(int x,int y)
{
	int f1=father(x),f2=father(y);
	val[f1]/=2,val[f2]/=2;
	int root1=merge(ch[f1][1],ch[f1][0]),
		root2=merge(ch[f2][1],ch[f2][0]),
		root3=merge(root1,root2);
	ch[f1][0]=ch[f2][0]=ch[f1][1]=ch[f2][1]=0;
	int	root4=merge(root3,f1),
		root5=merge(root4,f2);
	fa[root5]=fa[root4]=fa[root3]=fa[root2]=
	fa[root1]=fa[f1]=fa[f2]=fa[x]=fa[y]=root5;
	return val[root5];
}
int main()
{
	int n=read();
	for(int i=1;i<=n;i++)
		fa[i]=i,val[i]=read();
	int m=read();
	for(int i=1;i<=m;i++)
	{
		int x=read(),y=read();
		printf("%d\n",fight(x,y));
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值