欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  互联网

堆 + 模板题---数组模拟堆

程序员文章站 2022-06-28 15:38:31
题目描述维护一个集合,初始时集合为空,支持如下几种操作:“I x”,插入一个数x;“PM”,输出当前集合中的最小值;“DM”,删除当前集合中的最小值(数据保证此时的最小值唯一);“D k”,删除第k个插入的数;“C k x”,修改第k个插入的数,将其变为x;现在要进行N次操作,对于所有第2个操作,输出当前集合的最小值。输入格式第一行包含整数N。接下来N行,每行包含一个操作指令,操作指令为”I x”,”PM”,”DM”,”D k”或”C k x”中的一种。输出格式对于每个输出指令“P...

题目描述

维护一个集合,初始时集合为空,支持如下几种操作:
“I x”,插入一个数x;
“PM”,输出当前集合中的最小值;
“DM”,删除当前集合中的最小值(数据保证此时的最小值唯一);
“D k”,删除第k个插入的数;
“C k x”,修改第k个插入的数,将其变为x;
现在要进行N次操作,对于所有第2个操作,输出当前集合的最小值。
输入格式
第一行包含整数N。
接下来N行,每行包含一个操作指令,操作指令为”I x”,”PM”,”DM”,”D k”或”C k x”中的一种。
输出格式
对于每个输出指令“PM”,输出一个结果,表示当前集合中的最小值。
每个结果占一行。
数据范围
1≤N≤105
−109≤x≤109
数据保证合法。
输入样例:
8
I -10
PM
I -10
D 1
C 2 8
I 6
PM
DM
输出样例:
-10
6

题解

这里要注意的是heap_swap() 这个函数。
现在考虑要交换堆中的两个数3和5,其中3是第k个插入的数,在堆中的位置是size, 5是第m个插入的数,在堆中的位置是size/2.即hp[size] = k, ph[k] = size; hp[size/2]=m, ph[m] = size;
我们要交换3和5,不仅要交换这两个值,还要让他们的插入顺序这一信息跟着变动(如果不交换各自的插入顺序,那么5就变成第k个,3变成第m个)。那么,交换之后的结果应该是在堆中位置size存放5,且hp[size] = m,ph[m] = size; 同样在堆中位置size/2存放的是3,且hp[size/2] = k, ph[k] = size/2;
可以看到hp[], ph[]数组的值都要相互交换,于是就有了heap_swap()函数里面的操作:

代码

#include <iostream>
#include <string>
using namespace std;

const int N = 100010;
//ph[k] = m数组表示第k个插入的元素在数组中下标是m,
//hp[k] = m,表示数组下标是k的元素时第m次插入的
int h[N], ph[N], hp[N], cur_size; 

void heap_swap(int a, int b) //参数是数组下标
{
    //交换ph数组,这里要用到hp数组, 因为传入的参数是数组下标,而交换ph数组需要知道数组下标对应的第几个插入的,用hp数组查找
    swap(ph[hp[a]], ph[hp[b]]);
    
    //交换hp数组
    swap(hp[a], hp[b]);
    
    //交换值
    swap(h[a], h[b]);

}

void down(int u)
{
    int t = u;
    //改变u的指向
    if(2 * u <= cur_size && h[2 * u] < h[t]) t = 2 * u;
    if(2 * u + 1 <= cur_size && h[2 * u + 1] < h[t]) t = 2 * u + 1;
    if(u != t) //t有改变
    {
        heap_swap(u, t);
        down(t);
    }
}

void up(int u)
{
    while(u / 2 && h[u / 2] > h[u]) //h数组下标从1开始,u / 2 是 u 的父节点
    {
        heap_swap(u, u / 2);
        u >>= 1; //改变u的指向
    }
}

int main()
{
    int n;
    cin >> n;
    int m = 0; //记录第几个插入
    while(n--)
    {
        string op;
        int k, x;
        cin >> op;
        if(op=="I")
        {
            cin>>x;
            m++;
            h[++cur_size]=x;
            ph[m]=cur_size;
            hp[cur_size]=m;
            //down(size);
            up(cur_size);
        }
        else if(op=="PM")    cout<<h[1]<<endl;
        else if(op=="DM")
        {
            heap_swap(1,cur_size);
            cur_size--;
            down(1);
        }
        
        else if(op=="D")
        {
            cin>>k;
            int u=ph[k];                //这里一定要用u=ph[k]保存第k个插入点的下标
            heap_swap(u,cur_size);          //因为在此处heap_swap操作后ph[k]的值已经发生 
            cur_size--;                    //如果在up,down操作中仍然使用ph[k]作为参数就会发生错误
            up(u);
           down(u);
        }
 
        else if(op=="C")
        {
            cin>>k>>x;
            h[ph[k]]=x;                 //此处由于未涉及heap_swap操作且下面的up、down操作只会发生一个所以
            down(ph[k]);                //所以可直接传入ph[k]作为参数
            up(ph[k]);
        }
    }
    
    return 0;
}



本文地址:https://blog.csdn.net/xiaoxiongyuan__s/article/details/109276784