You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3.6 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

##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;
}