P3378 【模板】堆 (内含左偏树实现)

P3378 【模板】堆

题解

其实就是一个小根堆啦,STL就可以解决,但是拥有闲情雅致的我学习了Jelly_Goat的左偏树,增加了代码长度,妙啊

Solution 1 STL

STL 里面priority_queue默认是大根堆,修改一下变成小根堆

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<queue>

using namespace std;

typedef long long ll;

inline int read()
{
    int ans=0;
    char last=' ',ch=getchar();
    while(ch<'0'||ch>'9') last=ch,ch=getchar();
    while(ch>='0'&&ch<='9') ans=ans*10+ch-'0',ch=getchar();
    if(last=='-') ans=-ans;
    return ans;
}

int n,opr,x;
priority_queue<int,vector<int> ,greater<int> >h;

int main()
{
    n=read();
    while(n--)
    {
        opr=read();
        switch(opr)
        {
            case 1 : x=read();h.push(x);break;
            case 2 : printf("%d
",h.top() );break;
            case 3 : h.pop() ;break;
            default : break ; 
        }
    }
    return 0;
}

Solution 2 左偏树

安利 Jelly_Goat 神仙的blog

什么是左偏树呢?

就是一个类似二叉堆的东西,画出来像一个二叉树

前置芝士:

1.我们定一个节点的 distance 为他距离自己子树中最右边节点的距离,下面简称 dist 

   所以,没有右儿子的节点dist就是0啦

2.规定左偏树中,对于一个节点来说,他的左儿子的dist > 他的右儿子的dist

   然后这棵树整体就左偏啦

3.怎么计算dist???

   dfs跑一遍???

   其实也就是 dist [ fa ] = dist [ rson ] + 1 

   因为得到一个节点的dist一定是与他的右儿子有关的,既然之前知道了右儿子的dist,从右儿子转移过来,也就是dist [ rson ] + 1 ,不就得到自己的dist了吗

支持操作

1.merge 合并操作

   我们在用左偏树实现小根堆(大根堆也可以实现)

   假设我们要合并两个小左偏树 a,b

   (1)如果一个为空,直接返回另一个不就好啦

   (2)如果两个都不为空,那么我们就把他们的根节点权值较小的一个作为合并后的根节点,如果两个根节点的权值一样,那么就把dist较大的一个作为新根节点

 

   (3)然后继续往下面合并,假设新根是a,那么把b合并到他的右子树去,然后继续处理a的左右子树

   (4)get一下新根的dist

2.insert 插入操作

   get一个新的点,然后把他与原来的左偏树合并

3.top 访问堆顶 (左偏树实现小/大根堆)

   如果堆不为空,就输出堆顶元素,否则输出0

4.pop 弹出堆顶

   也就是把左偏树的根节点去掉,合并他的左右子树

5.size 记录一共多少个元素

   int cnt 记录,每次新加一个点 就cnt++,弹出一个点,就cnt--

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<queue>

using namespace std;

typedef long long ll;

inline int read()
{
    int ans=0;
    char last=' ',ch=getchar();
    while(ch<'0'||ch>'9') last=ch,ch=getchar();
    while(ch>='0'&&ch<='9') ans=ans*10+ch-'0',ch=getchar();
    if(last=='-') ans=-ans;
    return ans;
}

const int maxn=1e6+10;

struct Heapnode
{
    int lson=0,rson=0,val=0,dist=0;
};

struct Heap
{
    Heapnode tree[maxn];
    int cnt=0,tot=0,rt=0;
    inline int New(int val)
    {
        ++tot;
        tree[tot].val=val;
        return tot;
    }
    inline int set_dist(int a)
    {
        return tree[a].rson ? tree[tree[a].rson].dist+1 : 0;
    }
    int merge(int a,int b)
    {
        if(a==0||b==0) return a+b;
        else if(tree[a].val>tree[b].val) swap(a,b);
        else if(tree[a].val==tree[b].val&&tree[a].dist<tree[b].dist) swap(a,b);
        tree[a].rson=merge(tree[a].rson,b);
        if(tree[a].lson!=0&&tree[a].rson!=0){
            if(tree[tree[a].lson].dist<tree[tree[a].rson].dist)
               swap(tree[a].lson,tree[a].rson);
        } 
        else if(tree[a].lson==0&&tree[a].rson!=0)
            swap(tree[a].lson,tree[b].rson);
        set_dist(a);
        return a;
    }
    inline void insert(int val)
    {
        cnt++;
        int b=New(val);
        rt=merge(rt,b);
    }
    inline int top()
    {
        return rt?tree[rt].val:0;
    }
    inline void pop()
    {
        cnt--;
        int a=tree[rt].lson,b=tree[rt].rson;
        rt=merge(a,b);
    }
    inline int size()
    {
        return cnt;
    }
}h;

int n,opr,x;

int main()
{
    n=read();
    while(n--)
    {
        opr=read();
        switch(opr)
        {
            case 1 : x=read();h.insert(x);break;
            case 2 : printf("%d
",h.top() );break;
            case 3 : h.pop() ;break;
            default : break ; 
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/xiaoyezi-wink/p/11746851.html