题目链接:https://www.acwing.com/problem/content/description/841/
时/空限制:1s / 64MB
题目描述
维护一个集合,初始时集合为空,支持如下几种操作:
- “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≤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;
}