4078:实现堆结构【2018信科夏令营考前练习F】
-
总时间限制:
3000ms
-
单个测试点时间限制:
1000ms
-
内存限制:
65536kB
-
描述
定义一个数组,初始化为空。在数组上执行两种操作: 1、增添1个元素,把1个新的元素放入数组。 2、输出并删除数组中最小的数。 使用堆结构实现上述功能的高效算法。
-
输入
第一行输入一个整数n,代表操作的次数。 每次操作首先输入一个整数type。 当type=1,增添操作,接着输入一个整数u,代表要插入的元素。 当type=2,输出删除操作,输出并删除数组中最小的元素。 1<=n<=100000。
-
输出
每次删除操作输出被删除的数字。
-
样例输入
5 1 1 1 2 1 3 2 2
-
样例输出
1 2
-
提示
每组测试数据的复杂度为O(nlogn)的算法才能通过本次,否则会返回TLE(超时) 需要使用最小堆结构来实现本题的算法
题解
- 复习最小堆操作:
- 插入O(logn):插入到数组最后,然后从数组最后的位置不断shift up(如果小于父亲,则和父亲交换)
- 删除O(logn):将需要删除的元素和数组最后元素交换(然后注意更新元素个数,毕竟用这个判断是否还是树上的结点),然后从删除元素原先所在位置shift up(如果当前位置元素小于父亲,否则)或shift down
- (常见)删除堆顶O(logn):交换堆顶和数组最后元素,然后从堆顶位置shift down(如果孩子最小值小于其,则交换它和那个孩子)
- 构造O(n):顺序将输入元素存数组,然后从最后一个分支结点(即数组倒回去第一个不是叶结点的)倒回去shift down
#include <iostream>
using namespace std;
#define MAXN 100005
int heap[MAXN];
int sz;
void myswap(int l,int r)
{
int tmp=heap[l];
heap[l]=heap[r];
heap[r]=tmp;
}
int min_child_idx(int pos)
{
int l=2*pos+1;
if(l<sz){//has left child
if(l+1<sz){//has right child
if(heap[l]<heap[l+1]){
return l;
}
return l+1;
}
return l;
}
return l;
}
int main()
{
int n;
cin>>n;
int op;
int num;
sz=0;
int pos,par,child;
while(n--){
cin>>op;
if(op==1){//insert
cin>>num;
heap[sz]=num;
pos=sz;
++sz;
par=(pos-1)/2;
while(pos>0 && heap[par]>heap[pos]){
myswap(par,pos);
pos=par;
par=(pos-1)/2;
}
}
else{//delete top
cout<<heap[0]<<endl;
myswap(0,sz-1);
--sz;
pos=0;
child=min_child_idx(pos);
while(child<sz && heap[child]<heap[pos]){
myswap(child,pos);
pos=child;
child=min_child_idx(pos);
}
}
}
return 0;
}