堆(左偏树)

左偏树

定义一个节点的高度为到叶子节点的最短距离。
一棵左偏树需要满足几个性质:
\(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]]

pop

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

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

你可能感兴趣的:(堆(左偏树))