• 题解 P3377 【【模板】左偏树(可并堆)】


    所谓的左偏树,是一种可并堆的实现。

    这种数据结构能够支持高效的堆合并,但是不支持查询节点等操作,因此不同于平衡树,它的结构是不平衡的。

    左偏树满足如下两条基本性质:

    1. 堆的性质

    这也就是说左偏树每个节点的值都大于/小于它父节点的值。
    

    2. 对于任意节点,其左儿子距离不小于右儿子距离(左偏性质)

    这里需要先引入距离的概念。
    一个节点的距离,指它到后代中最近的外节点(儿子数量少于2)所经过的边数。
    

    有了上面两条性质,我们不难证明下面这条性质:

    3. 对于任意节点,其距离等于其右儿子距离+1

    其正确性是显然的,因为左儿子距离大于等于右儿子距离,所以最近的外节点必然在右儿子里。
    

    有了这些性质,我们就可以着手与其操作了。


    合并操作

    合并操作将两个左偏树合并在一起。

    假如两棵树中有空树,那么返回另一颗即可。

    否则取根节点更大/小的那一颗,然后将另一颗并到他的右儿子上去。

    由于并完之后右儿子距离可能比左儿子大,所以我们需要特判是否交换儿子。

    最后还要更新一下根节点的距离。

    int merge (int x,int y) {
    	if (!x||!y) return x+y;
        if (val[x]>val[y]) swap(x,y);
        heap[x].rs=merge(heap[x].rs,y);
        if (heap[heap[x].rs].size>heap[heap[x].ls].size) swap(heap[x].ls,heap[x].rs);
        heap[x].dis=heap[heap[x].rs].dis+1;
        return x;
    }
    

    删除操作

    没删么好说的,直接将左右儿子并起来就可以了。

    int erase (int x) {
    	x=merge(heap[x].ls,heap[x].rs);
        return x;
    }
    

    复杂度证明

    最后是左偏树合并操作的复杂度证明。

    由于我们每一次递归都合并右子树,而一颗树的距离取决于其右子树。

    所以最后一颗树被分解的次数不会超过其距离。

    也就是说,不会超过(log(n+1)-1)次。

    那么在最坏情况下,合并复杂度为(O(log(n_a+1)+log(n_b+1)-2))(O(log(a)+log(b)))也就是(O(log(ab)))

  • 相关阅读:
    生成操作 嵌入的资源
    用JavaScript操作CSS滤镜实现最近新闻旁边的“new”
    26个ASP.NET常用性能优化方法
    kafka集群搭建(windows环境下)
    AtCoder Beginner Contest 215 F Dist Max 2(二分、尺取)
    CodeForces 1487C Minimum Ties(建图、模拟)
    C#获取 URL参数
    编程给程序员带来哪些坏习惯
    【转载】IIS和服务器安全设置教程
    [转载]在IE8下动易SiteWeaver后台编辑器按钮没有反应的解决方案
  • 原文地址:https://www.cnblogs.com/ilverene/p/9850617.html
Copyright © 2020-2023  润新知