左偏树

  • 左偏树是可并堆的一种实现,它是一棵具有堆和左偏的性质的二叉树
  • 几个定义
    • 外顶点:左儿子或右儿子为空的顶点
    • 距离:该节点到子树中最近外顶点的距离(为了方便描述,默认空节点的距离为-1)
  • 每个节点记录的信息
    • 权值:满足父节点的权值 子节点权值(堆)
    • 距离:满足左节点的距离 右节点的距离(左偏)
  • 一些操作

    • 合并两个可并堆

      • 由于左偏的性质我们希望将小的左偏树插在右儿子上使得相对平衡些
      • 若一棵为空,另一棵树直接插在空节点的位置即可
      • 由于一棵左偏树中任意子树也是左偏树,假设当前要将树B合并到A中,根据堆的性质,若A的根顶的权值大于B,就交换A,B
      • BA,dis[lson[A]]<dis[rson[A]]lson[A]rson[A]
      • 每次插入后要更新当前根顶点的距离值
      • 合并的复杂度为 O(logsizeA+logsizeB)
      • 合并是左偏树的基础,就像Splay里的旋转一样
      • 返回值为以 a 为堆顶和以b为堆顶的堆合并后的堆顶
        function merge(a,b:longint):longint;
        begin
                if (a=0) then exit(b);
                if (b=0) then exit(a);
                if (val[a]>val[b]) then swap(a,b);
                rson[a]:=merge(rson[a],b);
                if (dis[lson[a]]<dis[rson[a]]) then swap(a,b);
                dis[a]:=dis[rson[a]]+1;
                exit(a);
        end;
    • 构建左偏树

      • 逐个顶点合并进去的复杂度为 O(NLogN)
      • 我们用一个队列,初始是每个点,每次从队列头取两个根顶合并为一个,将合并后的根顶扔到队列尾,直至队列中只剩一个
      • 复杂度为 O(N)
    • 插入/删除根顶
      • 插入就是和一个点合并
      • 删除根顶就是合并根顶的两个子树
    • 删除已知位置的节点

      • 左偏树不能像平衡树一样按照权值找到要删除的点
      • 设要删出的位置为 a ,p=fa[a]
      • 那么我们删掉 a 后,现将a的两个子堆合并, q=merge(lson[a],rson[a])
      • 然后将 q 的和p连起来
      • 然后一路向上修改 dis
      • 复杂度不超过 O(logN)

        procedure delete(a:longint);
        var p,q:longint;
        begin
                p:=fa[a];   
                q:=merge(lson[a],rson[a]);
                if (p<>0)and(lson[p]=a) then lson[p]:=q;
                if (p<>0)and(rson[p]=a) then rson[p]:=q;
                while (p<>0) do
                begin
                            if (dis[lson[p]]<dis[rson[p]]) then swap(lson[p],rson[p]);
                            if (dis[p]=dis[rson[p]]+1) then exit;
                            dis[p]:=dis[rson[p]]+1;
                            p:=fa[p];
                end;
        end;
  • [BZOJ1455] 罗马游戏

    • 题目大意
      支持
      • 1.合并两个团
      • 2.询问某个点所在的团的最小值,并删除
    • 题解
      • 合并两个堆
      • 删除堆顶
    • CODE
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值