一种可并堆,具有左偏性质。每个点有一个距离。
距离则是如下定义的:
节点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代码:
//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;
}