堆(左偏树)

Posted cjoiershiina-mashiro

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了堆(左偏树)相关的知识,希望对你有一定的参考价值。

左偏树

定义一个节点的高度为到叶子节点的最短距离。
一棵左偏树需要满足几个性质:
(1.)它是一个堆。
(2.)一个节点的左儿子的高度(ge)右儿子的高度。
(3.)一个节点的高度(=)右儿子的高度(+1)
由此可以得出一个节点数为(n)的左偏树的高度为(log (n+1)-1)
每个节点需要维护左右儿子和权值。
实际上要维护的是左偏树森林,所以同时用并查集维护每个节点所属左偏树的根。
左偏树只有一个核心操作:merge。

merge

merge实现合并两个节点所在的左偏树。
假如我们要合并的两棵左偏树的根是(u,v),不妨设(val_u)小于(val_v)
然后我们递归合并(u)的右儿子和(v)
可以发现我们递归合并之后右儿子的高度最多(+1),如果此时右儿子的高度大于左儿子了那就交换左右儿子。
最后维护一下并查集。

int merge(int u,int v)
{
    if(!u||!v) return u+v;
    if(val[u]>val[v]||(val[u]==val[v]&&u>v)) swap(u,v);
    ch[u][1]=merge(ch[u][1],v);
    if(h[ch[u][0]]<h[ch[u][1]]) swap(ch[u][0],ch[u][1]);
    return fa[ch[u][0]]=fa[ch[u][1]]=fa[u]=u,h[u]=h[ch[u][1]]+1,u;
}

pop

pop实现弹出某个节点所在左偏树的根。
直接把根(p)的左右儿子合并起来就好了。
但是因为原左偏树中有些点在并查集中只连到了(p),所以要把(p)在并查集里连到新的左偏树的根上去。

void pop(int p){val[p]=-1,fa[lc]=lc,fa[rc]=rc,fa[p]=merge(lc,rc);}

以上是关于堆(左偏树)的主要内容,如果未能解决你的问题,请参考以下文章

Chapter 5. 数据结构 左偏树

浅析左偏树的性质及其应用

模板左偏树

左偏树

左偏树总结

模板左偏树