落谷P1801 黑匣子
Posted sy666
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了落谷P1801 黑匣子相关的知识,希望对你有一定的参考价值。
题目链接:https://www.luogu.com.cn/problem/P1801
题目描述
Black Box是一种原始的数据库。它可以储存一个整数数组,还有一个特别的变量i。最开始的时候Black Box是空的.而i等于0。这个Black Box要处理一串命令。
命令只有两种:
ADD(x):把x元素放进BlackBox;
GET:i加1,然后输出Blackhox中第i小的数。
记住:第i小的数,就是Black Box里的数的按从小到大的顺序排序后的第i个元素。例如:
我们来演示一下一个有11个命令的命令串。(如下图所示)
现在要求找出对于给定的命令串的最好的处理方法。ADD和GET命令分别最多200000个。现在用两个整数数组来表示命令串:
1.A(1),A(2),…A(M):一串将要被放进Black Box的元素。每个数都是绝对值不超过2000000000的整数,M<=200000。例如上面的例子就是A=(3,1,-4,2,8,-1000,2)。
2.u(1),u(2),…u(N):表示第u(j)个元素被放进了Black Box里后就出现一个GET命令。例如上面的例子中u=(l,2,6,6)。输入数据不用判错。
输入格式
第一行,两个整数,M,N。
第二行,M个整数,表示A(l)……A(M)。
第三行,N个整数,表示u(l)……u(N)。
输出格式
输出Black Box根据命令串所得出的输出串,一个数字一行。
输入输出样例
7 4 3 1 -4 2 8 -1000 2 1 2 6 6
3 3 1 2
说明/提示
对于30%的数据,M≤10000;
对于50%的数据,M≤100000;
对于100%的数据,M≤200000。
从数据范围来看,这道题要求一个nlongn的算法,暴力排序是过不了的,需要用堆来解决问题。
建立一个大根堆b和一个小根堆a分别存储前i小的数和其他的数,用sj存储add命令,用u存储get命令。
由堆的性质可得a[1]为a中最小元素,b[1]为b中最大元素。
对于每一次add操作,如果此数s1比b[1]小,即比b中最大元素小,则将b[1]弹出在将此数s1加入b中,然后将弹出的数加入a中,否则直接将s1加入a中,保证b里存放的一定是BlackBox中前i小的数。
对于get操作,就将a[1]弹出加入b中并将此数输出,此数就是i自家1后第i小的数。
代码:
c:
#include<stdio.h> int a[200001],b[200001],lena=0,lenb=0,sj[200001],u[200001],lenu=1,m,n,q; void px(int l,int r){ int i,j,p,mid; i=l;j=r;mid=u[(l+r)/2]; do{ while(u[i]<mid)i++; while(u[j]>mid)j--; if(i<=j){ p=u[i];u[i]=u[j];u[j]=p; i++;j--; } }while(i<=j); if(i<r)px(i,r); if(l<j)px(l,j); return; } void puta(int d){ int now,next; a[++lena]=d; now=lena; while(now>1){ next=now>>1; if(a[now]>=a[next])break; q=a[now];a[now]=a[next];a[next]=q; now=next; } return; } int geta(){ int now,next,res; res=a[1]; a[1]=a[lena--]; now=1; while((now<<1)<=lena){ next=now<<1; if(next<lena&&a[next+1]<a[next])next++; if(a[now]<=a[next])break; q=a[now];a[now]=a[next];a[next]=q; now=next; } return res; } void putb(int d){ int now,next; b[++lenb]=d; now=lenb; while(now>1){ next=now>>1; if(b[now]<=b[next])break; q=b[now];b[now]=b[next];b[next]=q; now=next; } return; } int getb(){ int now,next,res; res=b[1]; b[1]=b[lenb--]; now=1; while((now<<1)<=lenb){ next=now<<1; if(next<lenb&&b[next+1]>b[next])next++; if(b[now]>=b[next])break; q=b[now];b[now]=b[next];b[next]=q; now=next; } return res; } int main(){ scanf("%d%d",&m,&n); for(int i=1;i<=m;i++)scanf("%d",sj+i); for(int i=1;i<=n;i++)scanf("%d",u+i); px(1,n); lenu=1; int e; for(int i=1;i<=m;i++){ e=sj[i]; if(lenb>=1&&sj[i]<b[1]){ e=getb(); putb(sj[i]); } puta(e); while(lenu<=n&&u[lenu]==i){ e=geta(); putb(e); printf("%d ",e); lenu++; } } return 0; }
pascal:
var a,b,sj,u:array[1..200000]of longint; lena,lenb,lenu,m,n,q:longint; procedure px (l,r:longint); var i,j,p,mid:longint; begin i:=l;j:=r; mid:=u[(l+r) div 2]; while i<=j do begin while u[i]<mid do i:=i+1; while u[j]>mid do j:=j-1; if i<=j then begin p:=u[i];u[i]:=u[j];u[j]:=p; i:=i+1;j:=j-1; end; end; if i<r then px(i,r); if l<j then px(l,j); exit(); end; procedure puta(d:longint); var now,next:longint; begin lena:=lena+1; a[lena]:=d; now:=lena; while now>1 do begin next:=now div 2; if a[now]>=a[next] then break; q:=a[now];a[now]:=a[next];a[next]:=q; now:=next; end; exit(); end; function geta():longint; var now,next,res:longint; begin res:=a[1]; a[1]:=a[lena]; lena:=lena-1; now:=1; while now*2<=lena do begin next:=now*2; if (next<lena)and(a[next+1]<a[next])then next:=next+1; if a[now]<=a[next] then break; q:=a[now];a[now]:=a[next];a[next]:=q; now:=next; end; exit(res); end; procedure putb(d:longint); var now,next:longint; begin lenb:=lenb+1; b[lenb]:=d; now:=lenb; while now>1 do begin next:=now div 2; if b[now]<=b[next] then break; q:=b[now];b[now]:=b[next];b[next]:=q; now:=next; end; exit(); end; function getb():longint; var now,next,res:longint; begin res:=b[1]; b[1]:=b[lenb]; lenb:=lenb-1; now:=1; while now*2<=lenb do begin next:=now*2; if (next<lenb)and(b[next+1]>b[next]) then next:=next+1; if b[now]>=b[next] then break; q:=b[now];b[now]:=b[next];b[next]:=q; now:=next; end; exit(res); end; var i,j,e:longint; begin readln(m,n); for i:=1 to m do read(sj[i]); for i:=1 to n do read(u[i]); px(1,n); lenu:=1; for i:=1 to m do begin e:=sj[i]; if (lenb>=1)and(sj[i]<b[1]) then begin e:=getb(); putb(sj[i]); end; puta(e); while (lenu<=n)and(u[lenu]=i) do begin e:=geta(); putb(e); writeln(e); lenu:=lenu+1; end; end; exit(); end.
c++STL版:
#include<stdio.h> #include<algorithm> using namespace std; int a[200001],b[200001],lena=0,lenb=0,sj[200001],u[200001],lenu=1,m,n,k; bool cmp(int k,int s){ return k>s; } int main(){ scanf("%d%d",&m,&n); for(int i=1;i<=m;i++)scanf("%d",sj+i); for(int i=1;i<=n;i++)scanf("%d",u+i); sort(u+1,u+n+1); lenu=1; int e; for(int i=1;i<=m;i++){ e=sj[i]; if(lenb>=1&&sj[i]<b[1]){ pop_heap(b+1,b+lenb+1); e=b[lenb]; b[lenb]=sj[i]; push_heap(b+1,b+lenb+1); } a[++lena]=e; push_heap(a+1,a+lena+1,cmp); while(lenu<=n&&u[lenu]==i){ pop_heap(a+1,a+lena+1,cmp); e=a[lena--]; b[++lenb]=e; push_heap(b+1,b+lenb+1); printf("%d ",e); lenu++; } } return 0; }
我可能写的不好,如果有问题,请帮忙指出,谢谢。
以上是关于落谷P1801 黑匣子的主要内容,如果未能解决你的问题,请参考以下文章