数据结构入门7—左偏树

来源:互联网 发布:js 字符串对象转数组 编辑:程序博客网 时间:2024/06/05 12:50

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

距离则是如下定义的: 

节点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;}