堆(左偏树)
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);}
以上是关于堆(左偏树)的主要内容,如果未能解决你的问题,请参考以下文章