Luogu P3378 【模板】堆

((^ 0.0 ^)    )~

堆是一个完全二叉树,对于小根堆,所有父节点<=子节点,下标就和线段树是一样的

在STL里就是优先队列

只有堆顶元素可以操作(询问或弹出)。

加入新元素时x,heap[++size] = x,下标t=size;

每次比较它和父节点(t/2)的大小,如果它较小就swap。

删除堆顶元素时,用最后一个元素heap[size--]覆盖heap[1],下标t=1;

每次比较它和左右两个儿子的大小,和较小的swap。

注意:

  • 下标t的值不能大于堆的size;
  • 我一开始是这么写的:
  • void del() {
    swap(heap[],heap[cnt--]);
    int t = ;
    while(t* <= cnt && (heap[t] > heap[t*] || heap[t] > heap[t*+])) {
    if(heap[t*+] < heap[t*] && t*+ <= cnt) {
    swap(heap[t],heap[t*+]);
    t = t*+;
    } else {
    swap(heap[t],heap[t*]);
    t *= ;
    }
    }
    }
    把swap(heap[1],heap[cnt--])改为heap[1] = heap[cnt--]就对了
  • 如果把最小的数x放到了下面,将最后一个数y从堆顶下移,判断到x的父亲时,一定有x<=y。因为判断是否交换时的条件是左右儿子有一个>y就继续循环,虽然此时判断x的下标>size,但是会默认和另一个儿子交换。
  • 如果最后一个值是空的时(为0)就更会翻车了!所以边界条件还是分别判断,这样swap也没问题啦。

代码如下

#include<cstdio>
#include<iostream> using namespace std;
const int maxn = ;
int heap[maxn],n,a,b,cnt; void insert(int x) {
heap[++cnt] = x;
int t = cnt;
while(heap[t] < heap[t/]) {
swap(heap[t],heap[t/]);
t/=;
}
} void del() {
heap[] = heap[cnt--];
int t = ;
while((t* <= cnt && heap[t] > heap[t*]) || (t*+ <= cnt && heap[t] > heap[t*+])) {
if(heap[t*+] < heap[t*] && t*+ <= cnt) {
swap(heap[t],heap[t*+]);
t = t*+;
} else {
swap(heap[t],heap[t*]);
t *= ;
}
}
} int main() {
scanf("%d",&n);
for(int i = ; i <= n; i++) {
scanf("%d",&a);
if(a == ) {
scanf("%d",&b);
insert(b);
}
if(a == ) {
if(cnt)printf("%d\n",heap[]);
}
if(a == ) {
del();
}
}
return ;
}
上一篇:3D中的旋转变换


下一篇:javaSE 第77节课