比较经典的一道题,以前在洛谷上做到过。

题意:
(原题是英文)
给出n个数字,n为奇数。依次读入这些数字,读入奇数个数的时候,输出当前已输入的数字中的中位数。
注意题目有多组数据。

思路:
算是套路题吧。
我们可以利用两个堆来维护中位数,具体的操作是这样的:
维护一个大顶堆一个小顶堆,接着我们每次维护当前的中位数x,保证大顶堆中的数都小于x,小顶堆中的数都大于等于x。
每次读入2个数,如果这两个数都比x要大,我们放入比x大的小顶堆中。接着我们把x放入大顶堆,从小顶堆中弹出堆顶元素就是新的中位数;
同理,如果这两个数比x要小,我们放入比x小的大顶堆中。接着我们把x放入小顶堆,从大顶堆中弹出堆顶元素作为新的中位数;
如果x介于两数中间,把小数放入大顶堆,大数放入小顶堆,中位数不变。
这样子我们相当于花O(n)扫了一遍读入的数字,每次维护堆中元素需要花费2*logn时间。
总时间复杂度可以认为是O(nlogn)

代码:

#include<bits/stdc++.h>
using namespace std;
priority_queue<int,vector<int>,greater<int> >q2; //小顶堆
priority_queue<int,vector<int>,less<int> >q1;  //大顶堆
int main()
{
    int T;
    cin>>T;
    while(T--){
        while(!q1.empty())q1.pop();
        while(!q2.empty())q2.pop();
        int idx,n;
        scanf("%d%d",&idx,&n);
        printf("%d %d\n",idx,n/2+1);
        int x,now,t=0;
        scanf("%d",&x);
        t++;
        now=x;
        printf("%d ",now);
        for(int i=1;i<=n/2;i++){
            int x,y;
            scanf("%d%d",&x,&y);
            t++;
            if(x>y)swap(x,y);
            if(x>now){
                q1.push(now);
                q2.push(x);
                q2.push(y);
                now=q2.top();
                q2.pop();
                printf("%d ",now);
            }
            else if(y<now){
                q2.push(now);
                q1.push(x);
                q1.push(y);
                now=q1.top();
                q1.pop();
                printf("%d ",now);
            }
            else {
                q1.push(x);
                q2.push(y);
                printf("%d ",now);
            }
            if(t%10==0)cout<<endl;
        }
       if(t%10)cout<<endl;
    }
    return 0;
}