《算法竞赛进阶指南》黑盒子

黑盒子代表一个原始的数据库。

它可以用来储存整数数组,并且它拥有一个特殊变量 ii。

在最开始,黑盒子是空的,并且 i=0i=0。

现在对黑盒子进行一系列的操作处理,操作包括以下两种:

  1. ADD(x):表示将 xx 加入到黑盒子中。
  2. GET:使 ii 增加 11,输出黑盒子中第 ii 小的数值(即将所有数按升序排序后的第 ii 个数)。

下面给出一个具体例子:

序号 操作        i     盒子内数(升序排列后)             输出的值 
1    ADD(3)      0     3   
2    GET         1     3                                    3 
3    ADD(1)      1     1, 3   
4    GET         2     1, 3                                 3 
5    ADD(-4)     2     -4, 1, 3   
6    ADD(2)      2     -4, 1, 2, 3   
7    ADD(8)      2     -4, 1, 2, 3, 8   
8    ADD(-1000)  2     -1000, -4, 1, 2, 3, 8   
9    GET         3     -1000, -4, 1, 2, 3, 8                1 
10   GET         4     -1000, -4, 1, 2, 3, 8                2 
11   ADD(2)      4     -1000, -4, 1, 2, 2, 3, 8   

为了方便描述,下面我们定义两个序列:

  1. A(1),A(2),…,A(M)A(1),A(2),…,A(M):这个序列由加入到黑盒子内的所有元素按加入顺序排列后得到,上例中的 AA 序列为 (3,1,−4,2,8,−1000,2)(3,1,−4,2,8,−1000,2)。
  2. u(1),u(2),…,u(N)u(1),u(2),…,u(N):这个序列的第 ii 项表示的是第 ii 次 GET 操作时,盒子内元素的数量。上例中的 uu 序列为 (1,2,6,6)(1,2,6,6)。

现在请你根据给出的序列 AA 和 uu 求出操作过程中输出的所有数值。

输入格式

输入包括三行。

第一行包含两个整数 MM 和 NN,表示 AA 序列和 uu 序列的长度。

第二行包含 MM 个整数,表示 AA 序列的每一个元素。

第三行包含 NN 个整数,表示 uu 序列的每一个元素。

同行每个数之间用空格隔开。

输出格式

输出操作过程中所有 GET 操作输出的数值。

每个数值占一行。

数据范围

|A(i)|≤2×109|A(i)|≤2×109,
1≤N≤M≤300001≤N≤M≤30000,
对于所有 pp(1≤p≤N1≤p≤N), p≤u(p)≤Mp≤u(p)≤M 成立。

输入样例:

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

输出样例:

3
3
1
2

解题思路:维护一个大根堆和小根堆,大根堆里所有元素都比小根堆里的元素小,
始终保持大根堆里的元素为i个,则每次大根堆的堆顶即为所求;
ADD操作:
{
    若当前加入的数要小于等于大根堆堆顶,则将其放入大根堆中
    否则放入小根堆中
}
GED操作
{
    将小根堆里堆顶放入大根堆中

#include <queue>
#include <vector>
#include <cstdio>
#include <iostream>

using namespace std;

const int N = 30010;

int n, m;
int a[N], b[N];

int main()
{
    cin >> n >> m;
    for (int i = 1; i <= n; i ++ ) scanf("%d", &a[i]);
    for (int j = 1; j <= m; j ++ ) scanf("%d", &b[j]);
    
    priority_queue<int> down;//大根堆
    priority_queue<int, vector<int>, greater<int>> up;//小根堆
    
    for (int i = 1, j = 1; i <= m; i ++ )
    {
        while (j <= b[i])//ADD操作
        {
            if (up.empty() || a[j] >= down.top()) up.push(a[j]);//放入小根堆
            else
            {
                down.push(a[j]);
                up.push(down.top());//始终保持大根堆里面有i个元素
                down.pop();
            }
            
            j ++ ;
        }
        
        down.push(up.top());//GED操作,将小根堆的堆顶放入大根堆,使得大根堆里始终保持i个数
        up.pop();
        printf("%d\n", down.top());//输出大根堆的堆顶即可
    }
    
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

啥也不会hh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值