其他分享
首页 > 其他分享> > [AcWing 839] 模拟堆

[AcWing 839] 模拟堆

作者:互联网

image
image


点击查看代码
#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;
}

  1. 维护小根堆的三个重要操作:
    ① heap_swap:当两个节点需要交换时,除了交换节点的值,还要把和编号之间的双向指针 hp 和 ph 交换(hp 表示堆节点指向编号节点, ph 表示编号节点指向堆节点);
    ② down:维护 u 节点及其以下的节点,当出现孩子节点的值小于父节点的值时,把这两个节点用 heap_swap 交换;
    ③ up:维护 u 节点及其以上的节点,当出现父节点的值大于孩子节点的值时,把两个节点用 hedp_swap 交换;(u 无论是左孩子还是右孩子,u / 2 都表示同一个父节点)
  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