堆的基本操作(手写模拟堆)

地址:https://www.acwing.com/problem/content/841/

堆的基本操作(手写模拟堆)

堆的基本操作(手写模拟堆)

解析:

这个题比较麻烦的一点就是k。第k个插入的数,不是树里的序号。经过一系列变换后,第k个插入的数在树里的序号会发生交换。

所以引入两个数组:ph[i]=x:表示第i次插入的数,在树中的序号为x。hp[i]=x:表示树中的序号i,是第x次插入的数。

乍一看,hp[]似乎并没有什么用,每次交换h[]和ph[]即可了。别急,请看下面:

我们来定义一个全新的交换方式:heap_swap(int u,int v)

u,v做为树的两个结点号被传了进来。

那么我们需要交换h[u],h[v],我们要交换两个ph[],但是,ph[]里的索引不知道,也就是说我们并不知道h[u],h[v]代表的数,是第几次插入的,自然就没法交换ph[]。

这个时候就可以看出hp[]的厉害了,hp[u],hp[v]不就是表示第几次插入的数吗?也就是ph的索引,至此,就可以交换ph[]了。有代码:

void heap_swap(int u,int v)
{
    swap(h[u],h[v]);
    swap(ph[hp[u]],ph[hp[v]]);
    swap(hp[u],hp[v]);
}

可以发现,顺序对结果是没有影响的~

关于堆,我有小笔记可供大家参考:https://www.cnblogs.com/liyexin/p/13942174.html

这个是本题的一个难点,其他的就是模板了,看注释吧:

#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
#include<map>
typedef long long ll;
const int maxn=1e5+10;
const int maxn2=3e6+10; 
int hp[maxn],ph[maxn],h[maxn],n,m,siz;
void heap_swap(int a,int b)
{
    swap(h[a],h[b]);
    swap(ph[hp[a]],ph[hp[b]]);
    swap(hp[a],hp[b]);
}
void down(int u)
{
    int t=u;
    if(u*2<=siz&&h[2*u]<h[t])
        t=2*u;
    if(2*u+1<=siz&&h[2*u+1]<h[t])
        t=2*u+1;
    if(u!=t)
    {
        heap_swap(u,t);
        down(t);
    }
}
void up(int u)
{
    while(u/2>=1&&h[u/2]>h[u])
    {
        heap_swap(u/2,u);
        u=u/2;
    }
}
int main()
{
    cin>>n;
    siz=0;//树的总大小
    m=0;//第几次插入
    while(n--)
    {
        char op[5];
        cin>>op;
        if(op[0]=='I')
        {
            int x;
            cin>>x;
            h[++siz]=x;//按照前面所说的,hp,ph的作用,进行值的更新
            ph[++m]=siz;
            hp[siz]=m;
            up(siz);//插到结尾,所以只需要up
        }
        else if(op[0]=='P')
        {
            cout<<h[1]<<endl;
        }
        else if(op[0]=='D'&&op[1]=='M')//删除最小
        {
            heap_swap(1,siz); //结尾覆盖上去,但是ph,hp会发生响应的改变,所以需要先进行连个值的交换,再down
            siz--;
            down(1);
        }
        else if(op[0]=='D')
        {
            int k;
            cin>>k;
            int u=ph[k];  //获取第k次插入的数在树中的下标
            heap_swap(u,siz);//删除,同样也可以先看成交换,再siz--
            siz--;
            up(u);
            down(u);
        }
        else
        {
            int k,x;
            cin>>k>>x;
            int u=ph[k];
            h[u]=x;
            down(u);
            up(u);
        }
    }
}

 

上一篇:P5829 【模板】失配树


下一篇:【笔记】主席树学习笔记