Skip to content

Lec4 Heaps

Lec4: Heaps

https://oi-wiki.org/ds/heap/

左偏树

OI-wiki写的吼啊

性质

dist的定义

  • 如果一个结点的左孩子或右孩子为空结点,则该结点的 dist 为 0,这种结点被称为外结点
  • 如果一个结点的左孩子和右孩子都不为空,则该结点的 \(dist(x)=\min(dist(lson_x),dist(rson_x))+1\)

对于左偏树 \(\forall x,dist(lson_x)\geq dist(rson_x)\),因此

\(dist(x)=dist(rson_x)+1\)

dist不是深度(因为外节点可能在链的中间),左偏树的深度可能是O(n)的,一条向左的链也是左偏树。

操作

合并

将两个堆合并,但保持堆的大小关系 。合并是最关键的操作,因为插入=合并原树和只有一个点的树。删除根=合并左右儿子。

  1. 比较当前两个子树根节点的值,选择较小的为根(记为x), 另一个为y
  2. 递归合并x的右儿子与y
  3. 检查是否满足左偏性质,如果不满足,则交换子树。

感性理解,时间复杂度取决于根节点一直向右儿子走的路径("右侧路径")长度, 这个长度越短越好.

(可视化)

    int merge(int x,int y){
        if(!x||!y) return x+y;
        if(tree[x].val>tree[y].val) swap(x,y);//根是小的
        rson(x)=merge(rson(x),y);//合并右儿子
        if(tree[lson(x)].dist<tree[rson(x)].dist)
            swap(lson(x),rson(x));
        tree[x].dist=tree[rson(x)].dist+1;//更新dist
        return x;
    }

时间复杂度

一棵有 n个节点的二叉树,根的 dist 不超过\(\log(n)+1\) \left\lceil\log (n+1)\right\rceil,因为一棵根的dist为x的二叉树至少有x-1层是满二叉树,那么就至少有 \(2^x-1\)个节点。注意这个性质是所有二叉树都具有的,并不是左偏树所特有的。

对于左偏树,每次递归dist会-1 因为\(dist(x)=dist(rson(x))+1\) 所以合并的复杂度是\(O(\log n)\)

斜堆

不需要dist的限制

操作

跟左偏树一样先比较根 .每次合并后回溯,交换左右儿子 (个人感觉还是递归从下到上好理解,虽然画图的工作量大) (也有不递归的写法)

skew heap合并时总是交换当前节点的左右儿子,但当当前节点是右路径上的最大节点时,不交换左右儿子。这个问题主要会影响合并的最后一步,最后一步的根节点是右路径上最大的(或者说它没有右子树)则不交换。

int merge(int x,int y){
    if(!x||!y) return x+y;
    if(tree[x].val>tree[y].val) swap(x,y);
    rson(x)=merge(rson(x),y);//优先合并右儿子
    swap(lson(x),rson(x));
    return x;
}

时间复杂度

参考

对于节点p,如果p的右子树的大小>=p子树大小/2, 就定义p为heavy node. 否则为light node

当p的右子树发生合并(包括交换)

  • 如果p是heavy, 那么p一定变成light.(因为右子树变的更大,交换后到了左边)
  • 如果p是light,那么p可能变成heavy
  • 合并过程中,如果一个节点的 heavy/light 发生变化,那么它原先一定在堆的最右侧路径上 (因为我们是沿着根节点一直往右走的, 不管是x还是y)

设在右侧路径上的heavy node数量为\(h_x,h_y\), light node为\(l_x,l_y\) 整棵树不在右侧路径的heavy node数量为\(h^0_x,h^0_y\)

定义势函数\(\Phi\)为当前树中 heavy node的总数量

\(c=t_{worst}+\Phi(H_{new})-\Phi(H_x)-\Phi(H_y)\)

  • \(t_{worst}\)为真实的cost(就是模板中的\(a_i\)) 最坏情况下是两树的右侧路径长度 \(h_x+l_x+h_y+l_y\)
  • \(\Phi(H_{new})=h_x^0+h_y^0+h'_x+h'_y \leq h_x^0+h_y^0+l_x+l_y\). 因为原来的\(h_x,h_y\)全部变成light了,而\(l_x,l_y\)有可能变成heavy

Comments