给你一个空的集合。两种操作,add(i)和get分别是把i加入到集合中去,将集合中的数从小到大排列,k++,然后输出第k个(k一开始是0)。现在让你按照他给出的流程疯狂操作,并输出每次get弹出的值。
最惨的情况就是add()和get操作各30000次。应该就是用一个堆吧,每次插入一个数需要logn,最慢就是不到nlogn,然后每次取出第k小的数需要klogn,取出操作最多不到n*n*logn。
然后无奈去网上查,用两个堆,两个。一个大顶堆,一个小顶堆,要求小顶堆的顶大于大顶堆。然后就是大顶堆里要有k个数,记大顶堆的顶为big,小顶堆的顶为small。(big<small)
插入a的操作:1.如果a>=big,那么,把a插入小顶堆;需要logn 2.如果a<big,那么,将其插入大顶堆,然后取出大顶堆的顶端元素插入到小顶堆里面。3logn弹出操作:1.先取出小顶堆堆顶输出,然后将小顶堆堆顶插入大顶堆中,最后弹出小顶堆堆顶。3logn
综合以上,时间复杂度O(nlogn)
#include<iostream>#include<stdio.h>#include<algorithm>#define N 30500using namespace std;int m,n;//m次输入操作以及n次输出操作 int a[N]={0};//要add的数 int b[N]={0};//第i个要get的次数为b[i]int big[N]={0};int small[N]={0};bool cmp(int x,int y){ return x>y;}void add(int x,int i,int k){ if(x>=big[0])//如果要插入的数大于大顶堆的顶,那么就把它插入小顶堆 { small[i-k-1]=x; push_heap(small,small+i-k,cmp); } else//不然就把它插入大顶堆,大顶堆最大的数弹出,插到小顶堆里 { big[k]=x; push_heap(big,big+k); small[i-k-1]=big[0]; push_heap(small,small+i-k,cmp); pop_heap(big,big+k+1); }}void get(int i,int k){ PRintf("%d/n",small[0]); big[k]=small[0]; push_heap(big,big+k+1); pop_heap(small,small+i-k,cmp);}void ceshi(){ cout<<"big: "; for(int i=0;i<m;i++) { cout<<big[i]<<" "; } cout<<endl; cout<<"small: "; for(int i=0;i<m;i++) { cout<<small[i]<<" "; } cout<<endl;}int main(){ cin>>m>>n; for(int i=1;i<=m;i++) { scanf("%d",&a[i]); } for(int i=1;i<=n;i++) { int l; scanf("%d",&l); b[l]++; } int k=0;//最大堆里面的数的个数 for(int i=1;i<=m;i++) { add(a[i],i,k); //ceshi(); while(b[i]!=0) { get(i,k); k++; b[i]--; //ceshi();cout<<endl; } }}
新闻热点
疑难解答