模拟堆(算法题)
#include <bits/stdc++.h>
using namespace std;const int N = 100010;
// h: 堆数组,存储元素值
// hp[i]: 堆中位置i的节点是第几次插入的(记录插入顺序)
// ph[k]: 第k次插入的节点当前在堆中的位置
// s: 当前堆的大小(元素个数)
int h[N], hp[N], ph[N], s;// 交换堆中位置u和v的两个节点,并维护ph和hp数组的映射关系
void heap_swap(int u, int v) {swap(h[u], h[v]); // 交换节点值swap(hp[u], hp[v]); // 交换节点的插入顺序记录// 根据交换后的hp值更新ph数组:// ph[hp[u]]指向u的位置,现在hp[u]的值已被交换,需更新对应ph项swap(ph[hp[u]], ph[hp[v]]);
}// 下沉操作:调整位置i的节点,维持小根堆性质
void down(int i) {int t = i; // t记录最小值的下标// 检查左子节点是否存在,且是否小于当前节点if (2 * i <= s && h[t] > h[2 * i]) t = 2 * i;// 检查右子节点是否存在,且是否小于当前最小值if (2 * i + 1 <= s && h[t] > h[2 * i + 1]) t = 2 * i + 1;if (t != i) { // 若子节点更小heap_swap(t, i); // 交换当前节点与最小子节点down(t); // 递归下沉调整}
}// 上浮操作:调整位置i的节点,维持小根堆性质
void up(int i) {// 若存在父节点且当前节点值小于父节点if (i / 2 > 0 && h[i] < h[i / 2]) {heap_swap(i, i / 2); // 与父节点交换up(i / 2); // 递归上浮调整}
}int main() {int n;cin >> n;int m = 0; // m记录插入操作的次数,即第m次插入while (n--) {string op;cin >> op;if (op == "I") { // 插入操作int x;cin >> x;m++; // 插入次数增加s++; // 堆大小增加h[s] = x; // 新元素插入堆末尾ph[m] = s; // 第m次插入的元素在堆中的位置是shp[s] = m; // 堆中位置s的元素是第m次插入的up(s); // 新元素可能比父节点小,需要上浮调整/*模拟插入过程:1. 将新元素x放在堆尾(位置s)2. 记录ph[m]=s(第m次插入对应位置s)3. 记录hp[s]=m(位置s的元素是第m次插入的)4. 从位置s向上调整堆*/}else if (op == "PM") { // 输出最小值(堆顶)cout << h[1] << endl;}else if (op == "DM") { // 删除最小值heap_swap(1, s); // 将堆顶与堆尾交换s--; // 堆大小减1,相当于删除原堆顶down(1); // 新的堆顶可能不符合堆性质,向下调整/*模拟删除最小值:1. 交换堆顶(位置1)和堆尾(位置s)2. 删除堆尾(s--)3. 从新堆顶(原堆尾元素)开始向下调整*/}else if (op == "D") { // 删除第k次插入的元素int k;cin >> k;int u = ph[k]; // 找到第k次插入的元素在堆中的位置uheap_swap(u, s); // 将该元素与堆尾交换s--; // 删除堆尾元素up(u); // 交换后u位置元素可能比父小,尝试上浮down(u); // 也可能比子大,尝试下沉(实际只会执行其中一个)/*模拟删除第k个插入的元素:1. 通过ph[k]找到该元素在堆中的位置u2. 交换位置u和s的元素3. 删除位置s元素(s--)4. 对位置u的元素执行一次上浮和下沉,确保堆性质恢复(因为交换后的元素可能比父小或比子大,需要调整)*/}else { // 修改第k次插入的元素的值int k, x;cin >> k >> x;int u = ph[k]; // 找到第k次插入的元素的位置uh[u] = x; // 修改值up(u); // 新值可能比父小,上浮调整down(u); // 或比子大,下沉调整(同样只会执行其一)/*模拟修改操作:1. 通过ph[k]找到元素位置u2. 修改h[u]为x3. 由于值改变,可能需要上浮或下沉来调整堆结构*/}}return 0;
}
本篇参考了acwing算法基础课。