洛谷1801 黑匣子_NOI导刊2010提高(06) 【好题】

洛谷1801 黑匣子_NOI导刊2010提高(06)
本题地址: http://www.luogu.org/problem/show?pid=1801

题目描述
Black Box是一种原始的数据库。它可以储存一个整数数组,还有一个特别的变量i。最开始的时候Black Box是空的.而i等于0。这个Black Box要处理一串命令。
命令只有两种:
ADD(x):把x元素放进BlackBox;
CET:i加l,然后输出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)个元素被放进了Blaek 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
l
2
说明
对于30%的数据,M≤10000;
对于50%的数据,M≤100000:
对于100%的数据,M≤200000。


好久没有打洛谷,重回竞技场,发现一道好题
题解:
这道题能用平衡树做,但用堆更方便
tsreaper大牛的博客帮助了我
GET:i加1,然后输出Blackhox中第i小的数”
如果GET操作不是按顺序询问,而是随机询问,那么平衡树自然是首选。但是GET操作是按顺序询问的,平衡树未免有点大材小用…….
所以,我们建立两个堆,一个小根堆hmin,一个大根堆hmax。一开始读入数据时,将数据加入hmin。进行GET操作时,输出hmin的堆顶,并将其移入hmax。
这样,hmax中存有的,就是当前黑箱中最小的i个数。当最新读入的数x比hmax的堆顶y要小时,说明x在新黑箱最小的i个数之中,相当于y的位置就被x挤掉了。那么就将y移回hmin。若x比y要大,则将x加入hmin。
这种双堆的技巧,也适用于求多个连续区间的中位数。

至于堆,c++的同学可以用stl 的优先队列priority_queue轻松实现

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<queue>

using namespace std;
const int maxn=200010;
int a[maxn];
priority_queue<int> qmax;
priority_queue<int, vector<int>, greater<int> > qmin;
int main()
{
    freopen("in.txt", "r", stdin);
    int m, n;
    scanf("%d%d", &m, &n);
    for (int i=1; i<=m; i++) scanf("%d", &a[i]);
    int j=1;
    for (int i=1; i<=n; i++)
    {
        int x;
        scanf("%d", &x);
        for (;j<=x; j++)
        {
            if (!qmax.empty() && a[j]<qmax.top()){
                qmin.push(qmax.top());
                qmax.pop();
                qmax.push(a[j]);
            }else qmin.push(a[j]);  
        }
        printf("%d\n", qmin.top());
        qmax.push(qmin.top());
        qmin.pop();
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值