AcWing
  • 首页
  • 题库
  • 题解
  • 分享
  • 问答
  • 活动
  • 应用
  • 吐槽
  • 登录/注册

AcWing 839. 模拟堆(含hp[]与ph[]的详细注释)    原题链接    简单

作者: 作者的头像   17835208153 ,  2021-01-14 18:01:35 ,  阅读 14


1


题目描述

维护一个集合,初始时集合为空,支持如下几种操作:

“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

算法1

  1. 除了维护一个堆之外,还开辟了两个额外的数组hp[]与ph[].
  2. hp[]用来存储第k个插入的数在堆中的下标.
  3. ph[]用来存储堆中各个下标的数是第几个插入的(k).

时间复杂度

nlogn

参考文献

y总算法基础课——模拟堆

C++ 代码

#include<iostream>
#include<algorithm>
#include<string.h>

using namespace std;

const int N = 1e5 + 10;

int h[N];           /* 堆                                                   */
int ph[N];          /* 存储第k个插入的数在堆中的下标                        */
int hp[N];          /* 存储堆中指定下标的值是第k个插入的数,与ph[N]互逆      */
int cnt;            /* 存储当前堆中用到了哪个下标,用于插入与删除等操作      */

void heap_swap(int a, int b)
{
    swap(ph[hp[a]], ph[hp[b]]); /* 1.先通过下标a找到h[a]在堆中是第几个插入的数
                                   2.再通过第几个插入的数k找到在ph中所记录的在
                                    堆中对应的下标 3.最后与b交换            */
    swap(hp[a], hp[b]);         /* 交换所记录的在堆中插入的值的顺序         */
    swap(h[a], h[b]);           /* 交换堆中的值                             */
}

void down(int u)
{
    int t = u;
    if (u * 2 <= cnt && h[u * 2] < h[t]) 
        t = u * 2;
    if (u * 2 + 1 <= cnt && h[u * 2 + 1] < h[t]) 
        t = u * 2 + 1;

    if (u != t)                 /* 如果u不是当前以u为根节点的堆的最小值     */
    {
        heap_swap(u , t);
        down(t);
    }
}

void up(int u)
{
    while (u / 2 && h[u] < h[u / 2]) {
        heap_swap(u, u / 2);
        u >>= 1;
    }
}

int main()
{
    int n, m = 0;
    cin >> n;
    while (n--) {
        char op[5];
        int k, x;
        cin >> op;
        if (!strcmp(op, "I")) {
            cin >> x;
            cnt ++;
            m ++;
            ph[m] = cnt;    /* 堆中第m个插入的数在堆中的下标是cnt   */
            hp[cnt] = m;    /* 堆中下标为cnt的数是在堆中是第m个插入的   */
            h[cnt] = x;
            up(cnt);
        }
        else if (!strcmp(op, "PM"))
            cout << h[1] << endl;
        else if (!strcmp(op, "DM")) {
            heap_swap(1, cnt);
            cnt --;
            down(1);
        }
        else if (!strcmp(op, "D")) {
            cin >> k;
            k = ph[k];                  /* 取得第k个插入的数在堆中的下标        */
            heap_swap(k, cnt);
            cnt --;
            up(k);
            down(k);
        }
        else if (!strcmp(op, "C")) {
            cin >> k >> x;
            k = ph[k];
            h[k] = x;
            up(k);
            down(k);
        }

    }

    return 0;
}


0 评论

你确定删除吗?

© 2018-2021 AcWing 版权所有  |  京ICP备17053197号-1
联系我们  |  常见问题
AcWing
请输入登录信息
更多登录方式: 微信图标 qq图标
请输入绑定的邮箱地址
请输入注册信息