数据结构入门7—左偏树

一种可并堆,具有左偏性质。每个点有一个距离。

距离则是如下定义的: 

节点i称为外节点(externalnode),当且仅当节点i的左子树或右子树为空( left(i) = NULL或right(i) = NULL );节点i的距离(dist(i))是节点i到它的后代中,最近的外节点所经过的边数。特别的,如果节点i本身是外节点,则它的距离为0;而空节点的距离规定为-1 (dist(NULL) =-1)。
 左偏树满足下面两条基本性质: 
1、堆性质
2、节点的左子节点的距离不小于右子节点的距离。 即dist(left(i))≥dist(right(i)) (左偏性质)。性质2是为了使我们可以以更小的代价(时间复杂度较小)插入节点或删除最小节点操作后维持堆性质。

左偏树的左右子树也是左偏树。如果不满足左偏条件,则将左右儿子交换。

模板题(洛谷)   模板题(bzoj1455)

bzoj1455代码:

//Serene
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
using namespace std;
const int maxn=1e6+10;
int n,m,fa[maxn],num[maxn],son[maxn][2],len[maxn];

int aa;char cc;
int read() {
	aa=0;cc=getchar();
	while(cc<'0'||cc>'9') cc=getchar();
	while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar();
	return aa;
}

int find(int x) {
	return x==fa[x]? x:find(fa[x]);
}

int merge(int x,int y) {
	if(!x||!y) return len[x]? x:y;
	if(num[x]>num[y]||(num[x]==num[y]&&y<x)) swap(x,y);
	if(son[x][1]) son[x][1]=merge(son[x][1],y);
	else son[x][1]=y;
	fa[son[x][1]]=x;
	if(!son[x][0]||len[son[x][1]]>len[son[x][0]]) swap(son[x][0],son[x][1]);
	len[x]=len[son[x][1]]+1;
	return x;
}

void del(int x) {
	if(!len[x]) {
		printf("0\n");
		return;
	}
	printf("%d\n",num[x]);
	fa[son[x][0]]=son[x][0];fa[son[x][1]]=son[x][1];
	if(son[x][1]&&son[x][0]) merge(son[x][0],son[x][1]);
	len[x]=0;son[x][0]=son[x][1]=0;
}

int main() {
	n=read();
	for(int i=1;i<=n;++i) fa[i]=i;
	for(int i=1;i<=n;++i) num[i]=read(),len[i]=1;
	char x;int y,z;m=read();
	for(int i=1;i<=m;++i) {
		x=getchar();
		while(x<'A'||x>'Z') x=getchar();
		y=read();y=find(y);
		if(x=='M') {
			z=read(); z=find(z);
			if(len[y]&&len[z]&&(y!=z)) merge(y,z);
		}
		else del(y);
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值