[AcWing 839] 模拟堆
作者:互联网
点击查看代码
#include<iostream>
using namespace std;
const int N = 1e5 + 10;
int h[N], sz, m;
int ph[N], hp[N];
void heap_swap(int a, int b)
{
swap(ph[hp[a]], ph[hp[b]]);
swap(hp[a], hp[b]);
swap(h[a], h[b]);
}
void down(int u)
{
int t = u;
if (2 * u <= sz && h[2 * u] < h[t]) t = 2 * u;
if (2 * u + 1 <= sz && h[2 * u + 1] < h[t]) t = 2 * u + 1;
if (t != u) {
heap_swap(u, t);
down(t);
}
}
void up(int u)
{
while (u / 2 && h[u / 2] > h[u]) {
heap_swap(u / 2, u);
u /= 2;
}
}
int main()
{
int n;
cin >> n;
while (n --) {
string s;
int k, x;
cin >> s;
if (s == "I") {
cin >> x;
sz ++;
m ++;
h[sz] = x;
ph[m] = sz, hp[sz]= m;
up(sz);
}
else if (s == "PM") cout << h[1] << endl;
else if (s == "DM") {
heap_swap(1, sz);
sz --;
down(1);
}
else if (s == "D") {
cin >> k;
k = ph[k];
heap_swap(k, sz);
sz --;
down(k), up(k);
}
else if (s == "C") {
cin >> k >> x;
k = ph[k];
h[k] = x;
down(k), up(k);
}
}
return 0;
}
- 维护小根堆的三个重要操作:
① heap_swap:当两个节点需要交换时,除了交换节点的值,还要把和编号之间的双向指针 hp 和 ph 交换(hp 表示堆节点指向编号节点, ph 表示编号节点指向堆节点);
② down:维护 u 节点及其以下的节点,当出现孩子节点的值小于父节点的值时,把这两个节点用 heap_swap 交换;
③ up:维护 u 节点及其以上的节点,当出现父节点的值大于孩子节点的值时,把两个节点用 hedp_swap 交换;(u 无论是左孩子还是右孩子,u / 2 都表示同一个父节点) - 在进行删除第 k 个插入的数这个操作时,需要先让 k = ph[ k ],然后再用 swap 交换 k 和 sz 的值,如果直接用 swap 交换 ph[ k ] 和 sz 的值,那么交换后,ph[ k ] 指向的是 sz,无法用 down 和 up 处理原来 k 指向的那个位置;(head_swap 不会交换数组中的下标,用 k 保存 p[ k ] 后,k 就一直是处理的那个节点对应的数组下标)
标签:sz,int,hp,839,swap,ph,节点,模拟,AcWing 来源: https://www.cnblogs.com/wKingYu/p/16218872.html