左偏树学习笔记

定义

堆,是一棵树,且每个节点的键值都大于等于 / 小于其父亲的键值。

左偏树是一种可合并的堆,可以以 O ( log ⁡ n ) O(\log n) O(logn) 的复杂度实现合并。

性质

左偏树满足堆的性质。

我们设定一个值 dist \text{dist} dist,定义外节点为左儿子或右儿子为空的节点。

外节点的 dist \text{dist} dist 1 1 1。非外节点的 dist \text{dist} dist 为它到它子树中最近的外节点的距离加 1 1 1。空节点 dis = 0 \text{dis}=0 dis=0

每个节点左儿子的 dist \text{dist} dist 大于右儿子的,左偏树中每个节点的 dist \text{dist} dist 都等于它右儿子的 dist \text{dist} dist 1 1 1

操作

  • 合并两个堆
  • 插入节点
  • 删除最小 / 大值(根)

实现

可以用 pb_ds 库实现。注意要加上以下两行:

#include <ext/pb_ds/priority_queue.hpp>
using namespace __gnu_pbds;

Portal.

以下代码实现的是合并和删除根节点操作。

#include <bits/stdc++.h>
#include <ext/pb_ds/priority_queue.hpp>
using namespace std;
using namespace __gnu_pbds;

struct node
{
    int id,v;
    bool friend operator < (node a,node b)
    {
        if(a.v!=b.v) return a.v>b.v;
        return a.id>b.id;
    }
};
const int maxn=1e5+5;
__gnu_pbds::priority_queue<node> q[maxn];
int fa[maxn];
bool vis[maxn];

int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}

int main()
{
    int n,m;cin>>n>>m;
    for(int i=1,tmp;i<=n;i++) cin>>tmp,q[i].push((node){i,tmp}),fa[i]=i;
    for(int op,i=1;i<=m;i++)
    {
        cin>>op;
        if(op==1)
        {
            int x,y;cin>>x>>y;
            int fx=find(x),fy=find(y);
            if(fx==fy||vis[x]||vis[y]) continue;
            fa[fx]=fy,q[fy].join(q[fx]);
        }
        else
        {
            int x;cin>>x;
            if(vis[x]) {cout<<"-1\n";continue;}
            else cout<<q[find(x)].top().v<<'\n',vis[q[find(x)].top().id]=1,q[find(x)].pop();
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值