对顶堆总结
这个玩意是可以动态维护第k大的值(比如中位数)
每次操作logn
我们要维护这两个堆。
我们可以以小根堆的堆顶为“分界线”
如果大于它,就加入小根堆
反之加入大根堆
如果两个堆的个数相差超过1,
就把多的那个堆的堆顶弹出来,加入另一个堆的堆顶
如果要求中位数的话,显然是两个堆中
个数多的那一个的堆顶,这很容易理解。
加入的操作是这样
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(); }
}
#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;
}