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

P3378 【模板】堆

 

 

题解

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

 

Solution 1 STL

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

 

 

#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\n",h.top() );break;
            case 3 : h.pop() ;break;
            default : break ; 
        }
    }
    return 0;
}

 

 

 

Solution 2 左偏树

安利 Jelly_Goat 神仙的blog学习

什么是左偏树呢?spa

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

前置芝士:

1.咱们定一个节点的 distance 为他距离本身子树中最右边节点的距离,下面简称 dist code

 

   因此,没有右儿子的节点dist就是0啦blog

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

   而后这棵树总体就左偏啦string

3.怎么计算dist???it

   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\n",h.top() );break;
            case 3 : h.pop() ;break;
            default : break ; 
        }
    }
    return 0;
}
相关文章
相关标签/搜索