题目传送门
一、手写堆的实现
#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
int heap[N];
int ph[N]; //position to heap 输入序号p与堆中序号h的映射关系
int hp[N]; //heap to position 堆中序号h与输入序号p的映射关系
int sz;
//交换两个堆中的元素(a,b是指堆中序号)
void heap_swap(int a, int b) {
swap(heap[a], heap[b]); //交换堆中序号a与序号b的元素值
swap(hp[a], hp[b]); //堆中序号与输入序号的映射关系
swap(ph[hp[a]], ph[hp[b]]); //输入序号与堆中序号的映射关系
}
void down(int u) {
int t = u;
if (u * 2 <= sz && heap[u * 2] < heap[t]) t = u * 2;
if (u * 2 + 1 <= sz && heap[u * 2 + 1] < heap[t]) t = u * 2 + 1;
if (u != t) {
heap_swap(u, t);
down(t);
}
}
void up(int u) {
while (u / 2 && heap[u] < heap[u / 2]) {
heap_swap(u, u / 2);
u /= 2;
}
}
int n, m;
int main() {
cin >> n;
while (n--) {
string op;
int k, x;
cin >> op;
if (op == "I") {
cin >> x;
m++; //输入的序号++
sz++; //堆内元素个数++
ph[m] = sz; //第m处插入的元素,它在堆中的号是sz
hp[sz] = m; //堆中sz号元素,它是第m个插入进来的
heap[sz] = x; //堆中sz号元素的值为x
up(sz);
}
if (op == "PM")printf("%d\n", heap[1]);
if (op == "DM") {
heap_swap(1, sz); //用堆中最后一个元素替换掉1号元素
sz--; //删除尾部元素
down(1); //重排
}
if (op == "D") {
cin >> k; //第k个输入序号
k = ph[k]; //通过ph获取到现在是堆中的堆中序号是多少
heap_swap(k, sz); //将第k个与最后一个交换
sz--; //删除尾部元素
down(k); //down一下,up一下
up(k);
}
if (op == "C") {
cin >> k >> x; //第k个输入序号,修改值为x
k = ph[k]; //根据输入序号,查找到堆中序号k
heap[k] = x; //将值修改为x
down(k); //down一下,up一下
up(k);
}
}
return 0;
}
二、STL堆的实现
#include <bits/stdc++.h>
using namespace std;
const int N = 500010;
int a[N], cnt;
multiset<int> s;
int n;
string t;
int x, k;
int main() {
//读入优化
ios::sync_with_stdio(false);
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> t;
if (t == "I") {//插入一个数
cin >> x;
s.insert(x);
//记录第几个是什么数
a[++cnt] = x;
}
//输出当前集合中的最小值
if (t == "PM") cout << *s.begin() << endl;
//删除当前集合中的最小值
//*s.begin()是堆顶值,即最小值
if (t == "DM")
//下面这句话的作用就是利用find找出堆顶的迭代器,然后利用s.erase进行删除
s.erase(s.find(*s.begin()));
//删除第k个插入的数
if (t == "D") {
cin >> x;
if (s.find(a[x]) != s.end())
s.erase(s.find(a[x]));
}
//修改第k个插入的数,将其变为x;
if (t == "C") {
cin >> k >> x;
if (s.find(a[k]) != s.end()) s.erase(s.find(a[k]));
a[k] = x;
s.insert(x);
}
}
return 0;
}