转:原
处理动态中位数等问题,灵活运用了堆的性质,本质是维护两个堆。
大根堆Q1:维护集合中较小值的部分的最大值。
小根堆Q2:维护集合中较大值的部分的最小值。
注意到两个堆中的元素各自是单调的,两个堆间也是单调的。也就是说,Q1中的任何一个元素都不大于Q2中的任何一个元素。
那么假设高度为权值,两个堆可以形象化的表示成:
插入操作:
priority_queue<int> q1; //大根堆
priority_queue<int, vector<int>, greater<int> > q2; //小根堆
inline void insert(int x)
{
if(!q2.size() || x > q2.top()) q2.push(x);
else q1.push(x);
if(q1.size() > q2.size() + 1) { q2.push(q1.top()); q1.pop(); }
if(q2.size() > q1.size() + 1) { q1.push(q2.top()); q2.pop(); }
}
例题
[ POJ 3784 ] Running Median
#include<cstdio>
#include<queue>
#define REP(i, a, b) for(register int i = (a); i < (b); i++)
#define _for(i, a, b) for(register int i = (a); i <= (b); i++)
using namespace std;
priority_queue<int> q1; //大根堆
priority_queue<int, vector<int>, greater<int> > q2; //小根堆
inline void insert(int x)
{
if(!q2.size() || x > q2.top()) q2.push(x);
else q1.push(x);
if(q1.size() > q2.size() + 1) { q2.push(q1.top()); q1.pop(); }
if(q2.size() > q1.size() + 1) { q1.push(q2.top()); q2.pop(); }
}
int main()
{
int T, n, id, mid;
scanf("%d", &T);
while(T--)
{
while(q1.size()) q1.pop();
while(q2.size()) q2.pop();
scanf("%d%d", &id, &n);
printf("%d %d\n", id, (n + 1) / 2);
int cnt = 0;
_for(i, 1, n)
{
int x; scanf("%d", &x);
insert(x);
if(i & 1)
{
printf("%d ", q1.size() > q2.size() ? q1.top() : q2.top());
if(++cnt == 10 && i != n) { puts(""); cnt -= 10; } //输出格式要注意
}
}
puts("");
}
return 0;
}