AcWing 839. 模拟堆

\(AcWing\) \(839\). 模拟堆

一、题目描述

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

  1. I x,插入一个数 \(x\)
  2. PM,输出当前集合中的最小值;
  3. DM,删除当前集合中的最小值(数据保证此时的最小值唯一);
  4. D k,删除第 \(k\) 个插入的数;
  5. C k x,修改第 \(k\) 个插入的数,将其变为 \(x\)

现在要进行 \(N\) 次操作,对于所有第 \(2\) 个操作,输出当前集合的最小值。

输入格式
第一行包含整数 \(N\)

接下来 \(N\) 行,每行包含一个操作指令,操作指令为 I xPMDMD kC k x 中的一种。

输出格式
对于每个输出指令 PM,输出一个结果,表示当前集合中的最小值。

每个结果占一行。

数据范围
\(1≤N≤10^5\)

\(−10^9≤x≤10^9\)

数据保证合法。

输入样例:

8
I -10
PM
I -10
D 1
C 2 8
I 6
PM
DM

输出样例:

-10
6

二、手写堆的实现

#include <bits/stdc++.h>

using namespace std;
const int N = 100010;
int h[N], sz; // 堆,堆中元素个数
int p[N];     // 输入序号 与 堆中序号映射关系 p[2]=3 表示第2个输入的,在堆中序号是3号
int q[N];     // 堆中序号 与 输入序号映射关系 q[3]=2 表示堆中序号3号,是第2个输入的
int n, idx;   // n:指令数,idx:输入序号

// 交换两个堆中的元素(a,b是指堆中序号)
void heap_swap(int a, int b) {
    swap(h[a], h[b]);       // 交换堆中序号a与序号b的元素值
    swap(q[a], q[b]);       // 输入序号交换
    swap(p[q[a]], p[q[b]]); // 输入序号与堆中序号的映射关系
}

void down(int u) {
    int t = u;
    // 换到左右儿子和u的最小值
    if (u * 2 <= sz && h[u * 2] < h[t]) t = u * 2;
    if (u * 2 + 1 <= sz && h[u * 2 + 1] < h[t]) t = u * 2 + 1;

    if (u != t) {
        heap_swap(u, t);
        down(t);
    }
}

void up(int u) {
    while (u / 2 && h[u] < h[u / 2]) { // 爹活着,比爹牛,上位!(玄武门事变?)
        heap_swap(u, u / 2);
        u /= 2;
    }
}

int main() {
    cin >> n;
    while (n--) {
        string op;
        int k, x;
        cin >> op;
        if (op == "I") {
            cin >> x;
            p[++idx] = ++sz; // ① 第idx个插入的元素,在堆中的序号是sz
            q[sz] = idx;     // ② 堆中sz号元素,它是第idx个插入进来的
            h[sz] = x;       // ③ 堆中sz号元素的值为x
            up(sz);
        }
        if (op == "PM") printf("%d\n", h[1]);
        if (op == "DM") {
            heap_swap(1, sz); // 用堆中最后一个元素替换掉1号元素
            sz--;             // 删除尾部元素
            down(1);          // 重排
        }
        if (op == "D") {
            cin >> k;         // 第k个输入序号
            k = p[k];         // 获得堆中序号
            heap_swap(sz, k); // 将第k个与最后一个交换
            sz--;             // 删除尾部元素
            down(k);          // down一下,up一下
            up(k);
        }
        if (op == "C") {
            cin >> k >> x; // 第k个输入序号,修改值为x
            k = p[k];      // 根据输入序号,查找到堆中序号k
            h[k] = x;      // 将值修改为x
            down(k);       // down一下,up一下
            up(k);
        }
    }
    return 0;
}
posted @ 2021-09-15 11:14  糖豆爸爸  阅读(316)  评论(1编辑  收藏  举报
Live2D