[POJ3784]Running Median(堆动态维护中位数)

传送门


  这题需要用到一个名为:“对顶堆”的小技巧
  我们以值建立一个大根堆,一个小根堆,假设我们现在的中位数是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;
}

猜你喜欢

转载自blog.csdn.net/cabi_zgx/article/details/80867275
今日推荐