黑盒子代表一个原始的数据库。
它可以用来储存整数数组,并且它拥有一个特殊变量 ii。
在最开始,黑盒子是空的,并且 i=0i=0。
现在对黑盒子进行一系列的操作处理,操作包括以下两种:
ADD(x)
:表示将 xx 加入到黑盒子中。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
为了方便描述,下面我们定义两个序列:
- 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)。
- 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;
}