AcWing - 模拟堆(堆&模拟)

题目链接:https://www.acwing.com/problem/content/description/841/
时/空限制:1s / 64MB

题目描述

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

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

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

输入格式

第一行包含整数N。

接下来N行,每行包含一个操作指令,操作指令为”I x”,”PM”,”DM”,”D k”或”C 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

解题思路

题意:维护一个集合,初始时集合为空,有5中操作,对于PM命令,输出当前集合中的最小值。
思路:这个题最重要的就是swap的方法,剩余的就模拟就行了,维护的是小根堆。

Accepted Code:

/* 
 * @Author: lzyws739307453 
 * @Language: C++ 
 */
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
// heap[N]存储堆中的值, heap[1]是堆顶,x的左儿子是2x, 右儿子是2x + 1
// ph[k]存储第k个插入的点在堆中的位置
// hp[k]存储堆中下标是k的点是第几个插入的
int heap[MAXN], hp[MAXN], ph[MAXN];
void heap_swap(int u, int v) {
    swap(ph[hp[u]], ph[hp[v]]);
    swap(hp[u], hp[v]);
    swap(heap[u], heap[v]);
}
void PercDown(int *spt, int u, int size) {
    int t = u;
    if ((u << 1) <= size && spt[u << 1] < spt[t])
        t = u << 1;
    if ((u << 1 | 1) <= size && spt[u << 1 | 1] < spt[t])
        t = u << 1 | 1;
    if (t != u) {
        heap_swap(t, u);
        PercDown(spt, t, size);
    }
}
void PercUp(int *spt, int u) {
    while ((u >> 1) && (spt[u] < spt[u >> 1])) {
        heap_swap(u, u >> 1);
        u >>= 1;
    }
}
int main() {
    int n, k, x, cnt = 0, size = 0;
    char opa, opb;
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        scanf(" %c%c", &opa, &opb);
        if (opa != 'P') {
            if (opa != 'D') {
                if (opa != 'C') {
                    scanf("%d", &x);
                    heap[++size] = x, ph[++cnt] = size, hp[size] = cnt;
                    PercUp(heap, size);
                }
                else {
                    scanf("%d%d", &k, &x);
                    int u = ph[k];
                    heap[u] = x;
                    PercUp(heap, u), PercDown(heap, u, size);
                }
            }
            else {
                if (opb != ' ') {
                    heap_swap(1, size--);
                    PercDown(heap, 1, size);
                }
                else {
                    scanf("%d", &k);
                    int u = ph[k];
                    heap_swap(u, size--);
                    PercUp(heap, u), PercDown(heap, u, size);
                }
            }
        }
        else printf("%d\n", heap[1]);
    }
    return 0;
}
展开阅读全文
©️2020 CSDN 皮肤主题: 代码科技 设计师: Amelia_0503 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值