【基础算法】黑匣子(BZOJ1194)

问题 D(1194): 【基础算法】黑匣子

时间限制: 1 Sec  内存限制: 64 MB
提交: 94  解决: 58
[提交][状态][我的提交]

题目描述

我们使用黑匣子的一个简单模型。它能存放一个整数序列和一个特定的变量i。初始时刻,黑匣子为空且i为0。这个黑匣子能执行两类命令:
   ADD x:把元素x放入黑匣子中(x的绝对值不超过2000000);   
        GET :先将黑匣子中的i的值加1,然后输出黑匣子中所有数中第i小的数(注意:这里第i小的数是指将黑匣子中所有的数由小到大排序后第i个位置的数);

现在给处N条ADD和M条GET命令,要求你输出每条GET命令执行后的值。   

例如N=7 M=4的一个例子:

输入

第一行两个整数N,M(M<N≤30000),表示ADD命令和GET命令的条数;

第二行:N个空格分开的整数,依次表示N次ADD命令的元素

第三行:M个空格分开的整数,依次表示M次GET命令在第几次ADD命令之后

输出

有M行,每行对应一条GET命令的输出结果

样例输入

 (如果复制到控制台无换行,可以先粘贴到文本编辑器,再复制)

7 4
3 1 -4 2 8 -1000 2
1 2 6 6

样例输出

3
3
1
2
分析:首先这道题是肯定不能大暴力的qnq,也不能用优先队列取出来了又塞回去,都是要T掉的2333333。应用两个堆或优先队列,一个小根堆(a),一个大根堆(b)(从a中弹出来的元素)。没一次add操作先把该元素和(b)比较,把大的一个塞进a。
p.s:b是空时直接进a,开始想b[0]为0,应该够小了,忘了TM还有负数,,,,,2333333莫名wa了一个中午23333qnq,,qnq
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
int n,m,num,sum1,sum2,reout,now=1;
int small[300010],big[300010],op[300010];
void build_small(int x,int m){
    int np;
    while(1){
        np=x*2;
        if(np>m) break ;
        if(np+1<=m&&small[np+1]<small[np])    np++;
        if(small[x]<small[np])   break ;
        swap(small[x],small[np]);
        x=np;
    }
}
void build_big(int x,int m){
    int np;
    while(1){
        np=x*2;
        if(np>m) break ;
        if(np+1<=m&&big[np+1]>big[np])    np++;
        if(big[x]>big[np])   break ;
        swap(big[x],big[np]);
        x=np;
    }
}
void up_build_small(int x,int m){
    int np;//根
    while(1){
        np=x/2;
        if(np<m) break ;
        if(small[x]>small[np])   break ;
        swap(small[np],small[x]);
        x=np;
    }
}
void up_build_big(int x,int m){
    int np;
    while(1){
        np=x/2;
        if(np<m) break ;
        if(big[np]>big[x])   break ;
        swap(big[np],big[x]);
        x=np;
    }
}
void putin_small(int x){
    small[++sum1]=x;
    if(sum1<=1)  return ;
    up_build_small(sum1,1);
}
void putin_big(int x){
    big[++sum2]=x;
    if(sum2<=1)  return ;
    up_build_big(sum2,1);
}
void popout_big(){
    swap(big[1],big[sum2]);
    build_big(1,--sum2);
}
void popout_small(){
    swap(small[1],small[sum1]);
    build_small(1,--sum1);
}
int main(){
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",&op[i]);
    for(int out=1;out<=m;out++){
        scanf("%d",&num);
        for(now=now;now<=num;now++){
            if(op[now]>big[1]||!sum2)
                putin_small(op[now]);
            else{ 
                putin_small(big[1]);
                popout_big();
                putin_big(op[now]);
            }
        }
        for(int i=1;i<=out-reout;i++){
            if(i==out-reout)
                printf("%d\n",small[1]);
            putin_big(small[1]);
            popout_small();
            reout++;
        }
    }
    return 0;
}


练习堆手写优先队列2333,插入元素时要从下往上维护堆23333333333
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章