【基礎算法】黑匣子(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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章