这题需要用到一个名为:“对顶堆”的小技巧
我们以值建立一个大根堆,一个小根堆,假设我们现在的中位数是x,那么用大根堆来储存小于等于x的元素,用小根堆来储存大于x的元素,这样的话,大根堆的堆顶就是x,也就是现在的动态中位数。 那么也就是说我们保证大根堆里的元素都是小于小根堆的,你可以想象这两个堆是“顶”在一起的,他们是两个胖子互相挤来挤去,他们夹着的就是动态中位数,同时我们还要保证这两个堆的元素数量差=1,这里假设大根堆比小根堆多1,才能保证这个中位数是在中间的位置(两个胖子要体重差不多)
实现的过程如下:
我们现在读入了一个新的数x
1、如果他比大根堆的堆顶要小,也就是说明他比当前中位数要小,那么把x插入大根堆
2、如果他比大根堆的堆顶要大,也就是说明他比当前中位数要打,那么把x插入小根堆
3、在维护的过程中如果发现大根堆比小根堆少,弹出小根堆的堆顶插入大根堆直至符合要求
4、在维护的过程中如果发现大根堆的size-小根堆的size>1 ,弹出大根堆的堆顶假如小根堆直至符合要求
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<queue>
#include<vector>
using namespace std;
const int N=10010;
priority_queue<int> p;
priority_queue<int , vector<int> , greater<int> > q;
int ans[N];
int main()
{
// freopen("a.in","r",stdin);
// freopen("a.out","w",stdout);
int T;scanf("%d",&T);
while(T--)
{
while(!p.empty()) p.pop();
while(!q.empty()) q.pop();
int ti,n; scanf("%d%d",&ti,&n);
int tmp=0;
for(int i=1;i<=n;i++)
{
int x;scanf("%d",&x);
if(p.empty()) p.push(x);
else
{
if(x>p.top()) q.push(x);
else p.push(x);
}
while(p.size()<q.size())
{
int t=q.top(); q.pop();
p.push(t);
}
while(q.size()<p.size()-1)
{
int t=p.top(); p.pop();
q.push(t);
}
if(i&1)
ans[++tmp]=p.top();
}
printf("%d %d\n",ti,n/2+1);
for(int i=1;i<=tmp;i++)
{
if(i%10==1) printf("%d",ans[i]);
else if(i%10==0) printf(" %d\n",ans[i]);
else printf(" %d",ans[i]);
}
printf("\n");
}
return 0;
}