维护一个集合,初始时集合为空,支持如下几种操作:
- “I x”,插入一个数x;
- “PM”,输出当前集合中的最小值;
- “DM”,删除当前集合中的最小值(数据保证此时的最小值唯一);
- “D k”,删除第k个插入的数;
- “C k x”,修改第k个插入的数,将其变为x;
现在要进行N次操作,对于所有第2个操作,输出当前集合的最小值。
输入格式
第一行包含整数N。
接下来N行,每行包含一个操作指令,操作指令为”I x”,”PM”,”DM”,”D k”或”C k x”中的一种。
输出格式
对于每个输出指令“PM”,输出一个结果,表示当前集合中的最小值。
每个结果占一行。
数据范围
1≤N≤1051≤N≤105
−109≤x≤109−109≤x≤109
数据保证合法。
输入样例:
8
I -10
PM
I -10
D 1
C 2 8
I 6
PM
DM
输出样例:
-10
6
个人理解:代码里的heap_swap交换映射操作
C++代码实现
#include<iostream> #include<algorithm> #include<string.h> using namespace std; const int N = 1e5 + 10; int n,m; int size; int h[N]; //需要从第几个插入的点里边找到我们的元素,又需要堆里边的元素找回去,找到是第几个插入的 //也就是第k个插入的点和堆里边的元素的映射 //表示第K个插入的下标是什么是哪一个点 int ph[N]; //表示堆里面的点是第几个插入的点 int 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(u*2 <= size && h[u*2] < h[t]) t = u*2; if(u*2 + 1 <= size && h[u*2 + 1] < h[t]) t = u*2+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(){ //初始化m记录当前是第几个插入的数 int n,m = 0; scanf("%d",&n); while(n --){ char op[10]; int k,x; scanf("%s",op); //strcmp是<string.h>库的一个比较字符串的函数,如果相同就等于0 if(!strcmp(op,"I")){ scanf("%d",&x); size++;//堆里边多一个元素 m++; //一开始堆里边的第m个插入元素就是在size这个位置 ph[m] = size; //一开始堆里边size这个位置上的数是第m个插入进来的 hp[size] = m; //当然也需要在堆中的size的位置上添加元素 h[size] = x; up(size);//将元素向上怼 } else if(!strcmp(op,"PM")) printf("%d ",h[1]); else if(!strcmp(op,"DM")) { heap_swap(1,size); size -- ; down(1); } else if(!strcmp(op,"D")){ scanf("%d",&k); //将第k个元素是第几个插入的取出来 k = ph[k]; heap_swap(k,size); size -- ; down(k),up(k); } else{ scanf("%d%d",&k,&x); //拿出第k个要插入的元素 k = ph[k]; h[k] = x; down(k); up(k); } } return 0; }