【对顶堆】 黑匣子
传送门
题解
在最开始,黑盒子是空的,并且\(i=0\)。
现在对黑盒子进行一系列的操作处理,操作包括以下两种:
- \(ADD(x)\):表示将\(x\)加入到黑盒子中。
- \(GET\):使\(i\)增加\(1\),输出黑盒子中第\(i\)小的数值(即将所有数按升序排序后的第\(i\)个数)。
定义两个序列
- \(A\)表示:这个序列由加入到黑盒子内的所有元素按加入顺序排列后得到
- \(U(1),U(2),\dots,U(N)\): 这个序列的第i项表示的是第\(i\)次\(GET\)操作时,盒子内元素的数量
根据给出的序列\(A\)和\(U\)求出操作过程中输出的所有数值。
数据范围
\(\begin{array}{l}|A(i)|<=2 * 10^{9} \\ 1 \leq N \leq M \leq 30000\end{array}\)
\(p(1 \leq p \leq N), p \leq u(p) \leq M\)
题解
用对顶堆来维护整个有序的序列
-
一个大根堆存的是当前不会输出的 \(1\sim i-1\) 个元素
-
一个小根堆存的是当前应输出的位置\(i\sim n\)后的元素
保证大根堆中的元素始终小于小根堆中的元素,因为输出的是当前有序的
-
大根堆中元素的个数来维护题目中的\(i\)指针
-
每次输出的时候都想大根堆中多加入一个元素即可
每次插入操作时候后进行检查,若大根堆空的或大根堆顶小于小根堆顶时
-
将当前元素插入到小根堆中,因为当前的元素可能输出
-
否则插入到大根堆,然后再将大根堆中的堆顶插入到小根堆中
- 这样防止了大根堆的堆顶大于小根堆的堆顶
Code
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<n;i++)
const int N=3e4+10;
int a[N],u[N];
int n,m;
int main()
{
cin>>n>>m;
rep(i,0,n) cin>>a[i];
rep(i,0,m) cin>>u[i];
priority_queue<int> mx;
priority_queue<int,vector<int>,greater<int>> mi;
int i=0,j=0;
while(j < m)
{
while(i == u[j])
{
cout<<mi.top()<<endl;
mx.push(mi.top());
mi.pop();
j++;
}
int x=a[i];
if(mx.empty() || x > mi.top())
mi.push(x);
else
{
mx.push(x);
mi.push(mx.top());
mx.pop();
}
i++;
}
}

浙公网安备 33010602011771号