落谷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根据命令串所得出的输出串,一个数字一行。

输入输出样例

输入 #1
7 4
3 1 -4 2 8 -1000 2
1 2 6 6
输出 #1
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 黑匣子的主要内容,如果未能解决你的问题,请参考以下文章

P1801 黑匣子[堆]

洛谷 [P1801] 黑匣子

洛谷P1801 黑匣子

洛谷P1801黑匣子_NOI导刊2010提高(06)

洛谷堆P1801 黑匣子_NOI导刊2010提高(06)

题解 P1801 黑匣子_NOI导刊2010提高(06)