浅贪 对顶堆
其实这个东西的本质还是特别简单的:就是使用两个priority_queue来维护一下即可。
具体地,我们维护一个小根堆和一个大根堆,这里以查询第 \(k\) 大为例进行讲解(也就是说第 \(k\) 小反着来就可以了):
-
既然我们是求第 \(k\) 大,那我们可以用小根堆维护当前的前 \(k\) 大的数值,用大根堆维护剩下的。
-
之后就是插入操作(设小根堆的堆顶值为 \(x\),当前插入的数为 \(y\))
-
如果小根堆为空,或者 \(y\ge x\)
就将 \(y\) 搞到小根堆里
-
否则,就将 \(y\) 搞到大根堆里
-
-
如果当前的 \(k\) 变化,那我们就顺势调整大根堆和小根堆
例题
在这个题目中,我们发现我们需要得到第 \(k\) 小,同时我们还可以发现性质,就是添加一个数,中位数所在的位置只可能不动或者 \(\pm 1\) .
那就做完了:
#include <bits/stdc++.h>
using namespace std;
#define il inline
int n;
priority_queue<int >q1;
priority_queue<int,vector<int>,greater<int> >q2;
il void solve() {
if(n==-1) {
cout<<q1.top()<<'\n';q1.pop();
} else {
if(q1.size()==0||n<=q1.top())q1.push(n);
else q2.push(n);
}int sum=q1.size()+q2.size();
if(q1.size()<(sum+1)/2) {
q1.push(q2.top());q2.pop();
}if(q1.size()>(sum+1)/2) {
q2.push(q1.top());q1.pop();
}
}
int main() {
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int T;cin>>T;while(T--) {
while(q1.size())q1.pop();while(q2.size())q2.pop();
while(1){cin>>n;if(!n)break;solve();}
}
return 0;
}

浙公网安备 33010602011771号