先看了一下《算法》,大概懂了基本原理之后,先抄了一遍题解,然后做了一遍。做的时候发现了几处错误,第五次的时候成功AC
代码:
#include<cstdio>
#include<iostream>
#include<cctype>
using namespace std;
int heap[50001];
int heap_size=0;
inline int readint(){
char c=getchar();
while(!isdigit(c)){
c=getchar();
}
int n=0;
while(isdigit(c)){
n=n*10+c-'0';
c=getchar();
}
return n;
}
void put(int a){
int now,next;
heap[++heap_size]=a;
now=heap_size;
while(now>1){
next=now/2;
if(heap[now]>=heap[next])return;
swap(heap[now],heap[next]);
now=next;
}
}
void del(){
int now,next;
heap[1]=heap[heap_size--];//heap[1]=0;swap(heap[1],heap[heap_size]);
now=1;
while(now*2<=heap_size){//注意:这里应该是 now*2<=heap_size 而不是next<heap_size 或 next<=heap_size
next=now*2;
if(heap[next+1]<heap[next])next++;//if(heap[next]<heap[next+1])next++;
if(heap[next]>=heap[now])return;
swap(heap[next],heap[now]);
now=next;
}
}
int get(){
return heap[1];
}
int main(){
int n;
cin>>n;
for(int i=0;i<n;i++){
int input;
input=readint();
//cout<<"INPUT: "<<input;
if(input==1){
int input2;
input2=readint();
//cout<<"read 2";
put(input2);
}else if(input==2){
cout<<get()<<endl;
}else if(input==3){
del();
}
}
}
小根堆:
1.插入
假设你已经有一个堆了,就是上面那个
这个时候你如果想要给它加入一个节点怎么办,比如说0?
先插到堆底(严格意义上来说其实0是在5的左儿子的,图没画好放不下去,不过也不影响)
然后你会发现它比它的父亲小啊,那怎么办?不符合小根堆的性质了啊,那就交换一下他们的位置
交换之后还是发现不符合小根堆的性质,那么再换
还是不行,再换
好了,这下就符合小根堆的性质了,是不是顺眼很多了?(假的,图越来越丑,原谅我不想再画)
事实上堆的插入就是把新的元素放到堆底,然后检查它是否符合堆的性质,如果符合就丢在那里了,如果不符合,那就和它的父亲交换一下,一直交换交换交换,直到符合堆的性质,那么就插入完成了
2.删除
把0插入完以后,忽然你看这个0不爽了,本来都是正整数,怎么就混进来你这个0?
于是这时候你就想把它删除掉
怎么删除?在删除的过程中还是要维护小根堆的性质
如果你直接删掉了,那就没有堆顶了,这个堆就直接乱了,所以我们要保证删除后这一整个堆还是个完好的小根堆
首先在它的两个儿子里面,找一个比较小的,和它交换一下,但是还是没法删除,因为下方还有节点,那就继续交换
还是不行,再换
再换
好了,这个碍眼的东西终于的下面终于没有节点了,这时候直接把它扔掉就好了
这样我们就完成了删除操作,但是在实际的代码操作中,并不是这样进行删除操作的,有一定的微调,代码中是直接把堆顶和堆底交换一下,然后把交换后的堆顶不断与它的子节点交换,直到这个堆重新符合堆性质(但是上面的方式好理解啊)
(以上内容出自这里)
题目地址:https://www.luogu.org/problemnew/show/P3378