堆
题目描述
如题,初始小根堆为空,我们需要支持以下3种操作:
操作1: 1 x 表示将x插入到堆中
操作2: 2 输出该小根堆内的最小数
操作3: 3 删除该小根堆内的最小数
输入格式
第一行包含一个整数N,表示操作的个数
接下来N行,每行包含1个或2个正整数,表示三种操作,格式如下:
操作1: 1 x
操作2: 2
操作3: 3
输出格式
包含若干行正整数,每行依次对应一个操作2的结果。
输入输出样例
输入 #1
5 1 2 1 5 2 3 2
输出 #1
2 5
说明/提示
时空限制:1000ms,128M
数据规模:
对于30%的数据:N<=15
对于70%的数据:N<=10000
对于100%的数据:N<=1000000(注意是6个0。。。不过不要害怕,经过作者实测,堆是可以AC的)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int a[1000100],size,n,op; void judge(int p) { int m=p; if(a[p]>a[p<<1]&&(p<<1)<=size) { m=p<<1; } if(a[m]>a[(p<<1)+1]&&(p<<1)<=size-1) { m=(p<<1)+1; } if(p!=m) { swap(a[p],a[m]); judge(m); } } void insert(int x) { size++; a[size]=x; int p=size; while(p>=1&&a[p>>1]>a[p]) { swap(a[p],a[p>>1]); p=p>>1; } } void del() { swap(a[1],a[size]); size--; judge(1); } int main() { int x; scanf("%d",&n); while(n--) { scanf("%d",&op); if(op==1) { scanf("%d",&x); insert(x); } else if(op==2) printf("%d\n",a[1]); else del(); } return 0; }
问题:为什么插入需要倒着维护而删除需要正向维护?
原因:对于一个堆,关于节点的操作只影响节点本身和其父节点的性质而不影响其子节点的性质。插入的位置在最后,只可能影响本节点和其父节点的性质,删除位置在最前,只影响本节点,故向下维护,