左偏树学习笔记

定义

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

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

左偏树学习笔记_第1张图片

性质

左偏树满足堆的性质。

我们设定一个值 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 
using namespace __gnu_pbds;

Portal.

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

#include 
#include 
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;
}

你可能感兴趣的:(#,树形数据结构,数据结构)