8
16
2015
0

[题解][NOI导刊2010提高(06)]黑匣子

[好题] 关键字:双堆技巧。

Link&Limit


[洛谷1801]  [codevs2573]

时间限制:1000ms  空间限制:65536kb

Description


Black Box是一种原始的数据库。它可以储存一个整数数组,还有一个特别的变量i。最开始的时候Black Box是空的.而i等于0。这个Black Box要处理一串命令。

命令只有两种:

ADD(x):把x元素放进BlackBox;

CET:i加l,然后输出Blackhox中第i小的数。

记住:第i小的数,就是Black Box里的数的按从小到大的顺序排序后的第i个元素。例如:

我们来演示一下一个有11个命令的命令串。(如下图所示)
[题解][NOI导刊2010提高(06)]黑匣子 - TsReaper - TsReaper的博客

现在要求找出对于给定的命令串的最好的处理方法。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)。输入数据不用判错。

Input Format


第一行,两个整数,M,N。

第二行,M个整数,表示A(l)……A(M)。

第三行,N个整数,表示u(l)…u(N)。

Output Format


输出Black Box根据命令串所得出的输出串,一个数字一行。

Sample Input #1


7 4

3 1 -4 2 8-1000 2

1 2 6 6

Sample Output #1


3

3

1

2

Hint


对于30%的数据,M≤10000;

对于50%的数据,M≤100000;

对于100%的数据,M≤200000。

使用平衡树也可以完成这道题。但是题目中有一个值得关注的细节:

"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。

这种双堆的技巧,也适用于求多个连续区间的中位数。

#include <cstdio>
struct heap
{
    int h[200100],tot;
    heap() { tot = 0;}
    
    void add(int x)
    {
        int i = ++tot,j = i>>1;
        h[tot] = x;
        for(;i>1;i=j,j>>=1)
        {
            if(x>h[j]) {h[i] = h[j]; h[j] = x;}
            else break;
        }
    }
    
    void del()
    {
        int i = 1,j = 2,x = h[1] = h[tot--];
        for(;j<=tot;i=j,j<<=1)
        {
            if(j<tot) if(h[j+1]>h[j]) j++;
            if(x<h[j]) {h[i] = h[j]; h[j] = x;}
            else break;
        }
    }
}heap1,heap2;

int n,m,list[200010];

int main()
{
    int i,q;
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++) scanf("%d",&list[i]);
    for(i=1;m;m--)
    {
        scanf("%d",&q);
        for(;i<=q;i++)
        {
            heap1.add(list[i]);
            heap2.add(-heap1.h[1]);
            heap1.del();
        }
        printf("%d\n",-heap2.h[1]);
        heap1.add(-heap2.h[1]);
        heap2.del();
    }
    return 0;
}
Category: 题解 | Tags: codevs 洛谷 好题 | Read Count: 516

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter

| Theme: Aeros 2.0 by TheBuckmaker.com