堆操作:
难点:删除第k个插入的数,但是在堆里面是以下标的形式储存的,所以要搞清楚第k个插入的数对应在堆中的下标是什么,所以在这里开一个数组来维护
ph[k] = i
用来储存第k个插入的点在堆中对应的下标是啥
hp[i] = k
用来储存堆中下标为i的点对应的是第几个插入得点
难点一在于映射关系的建立,其次映射关系的维护也是一大操作难点,所以在交换堆的元素时,应该维护所建立的映射关系,所以在这里要创建独特的堆的交换函数,不能直接交换,打乱映射关系:
//交换两个堆元素的下标
void heap_swap(int a, int b){
swap(ph[hp[a]], ph[hp[b]]);
swap(hp[a], hp[b]);
swap(h[a], h[b]);
}
模拟堆代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
int hp[N], ph[N], h[N];
int sizes;
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 up(int u){
while (u / 2 && h[u / 2] > h[u]) {
heap_swap(u / 2, u);
u /= 2;
}
}
void down(int u){
int t = u;
if (u * 2 <= sizes && h[u * 2] < h[t]) t = u * 2;
if (u * 2 + 1 <= sizes && h[u * 2 + 1] < h[t]) t = u * 2 + 1;
if (u != t) {
heap_swap(u, t);
down(t);
}
}
int main(){
int n, m = 0;
scanf("%d", &n);
while (n -- ){
char op[5];
int k, x;
scanf("%s", op);
if (!strcmp(op, "I")) {
scanf("%d", &x);
m ++ ;
sizes ++ ;
ph[m] = sizes, hp[sizes] = m;
h[sizes] = x;
up(sizes);
}
else if (!strcmp(op, "PM")) printf("%d\n", h[1]);
else if (!strcmp(op, "DM")) {
heap_swap(1, sizes);
sizes -- ;
down(1);
}
else if (!strcmp(op, "D")) {
scanf("%d", &k);
k = ph[k];
heap_swap(k, sizes);
sizes -- ;
up(k), down(k);
}
else {
scanf("%d%d", &k, &x);
k = ph[k];
h[k] = x;
down(k), up(k);
}
}
return 0;
}
注解:和没有插入第k个数的操作完全一样,只不过为了维护映射关系把所有的swap操作都换成了heap_swap(),以保证在交换出的过程中维护数据