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≤105
?109≤x≤109
数据保证合法。

输入样例:

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

输出样例:

-10
6

方法一:

模拟堆,没什么技巧,麻烦的地方在于要维护第k个插入的数在堆中的下标,以及在堆中下标n的数是第几个插入的数...代码菜鸡调了一小时bug

#include 

using namespace std;

int n, nums[100010], cnt,
i2n[100010], n2i[100010], // i2n: 第i个插入的数在堆中位置    n2i: 在堆中n位置的数是第几个插入
idx;

void down(int u) {
    while (true) {
        int t = u;
        if (2 * u <= cnt && nums[t] > nums[2 * u]) t = 2 * u;
        if (2 * u + 1 <= cnt && nums[t] > nums[2 * u + 1]) t = 2 * u + 1;
        if (t == u) break;

        swap(nums[u], nums[t]);
        swap(n2i[u], n2i[t]);
        swap(i2n[n2i[u]], i2n[n2i[t]]);
        u = t;
    }
}

void up(int u) {
    while (u/2 > 0 && nums[u/2] > nums[u]) {
        swap(nums[u/2], nums[u]);
        swap(n2i[u/2], n2i[u]);
        swap(i2n[n2i[u/2]], i2n[n2i[u]]);
        u >>= 1;
    }
}

void insert(int x) {
    nums[++cnt] = x;
    ++idx;
    i2n[idx] = cnt;
    n2i[cnt] = idx;

    up(cnt);
}

void del(int k) {
    int nh = i2n[k];
    i2n[n2i[cnt]] = nh;
    n2i[nh] = n2i[cnt];
    nums[nh] = nums[cnt--];

    down(nh);
    up(nh);
}

void update(int k, int x) {
    int nh = i2n[k];
    nums[nh] = x;

    down(nh);
    up(nh);
}

void delmin() {
    n2i[1] = n2i[cnt];
    i2n[n2i[1]] = 1;
    nums[1] = nums[cnt--];

    down(1);
}

int main() {
    char op[3];
    scanf("%d", &n);
    while (n--) {
        int k, x;
        scanf("%s", op);
        if (op[0] == 'I') {
            scanf("%d", &x);
            insert(x);
        } else if (op[0] == 'P') {
            printf("%d\n", nums[1]);
        } else if (op[0] == 'D' && op[1] == 'M') {
            delmin();
        } else if (op[0] == 'D') {
            scanf("%d", &k);
            del(k);
        } else if (op[0] == 'C') {
            scanf("%d%d", &k, &x);
            update(k, x);
        }
    }
}