Solution

经典的动态维护序列中位数问题。

采用对顶堆做法:维护一个大根堆和一个小根堆,其中大根堆维护当前序列中较小的一半元素,小根堆维护较大的一半元素。依次插入每个元素:

  • 若当前元素小于小根堆堆顶,则插入大根堆。
  • 若当前元素大于等于小根堆堆顶,则插入小根堆。

每插入一个元素,检查当前两个堆的大小之差是否超过 ,若超过 ,则调整为相等大小。这样,每到序列有奇数位时,元素较多的堆的堆顶即为当前序列的中位数。

时间复杂度:

Code

#include<iostream>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;
int s,t,n,x;
int fr(){
    char ch;
    int sum,sign=1;
    while((ch=getchar())>'9'||ch<'0')
        if(ch=='-')
            sign=-1;
    sum=ch-'0';
    while((ch=getchar())>='0'&&ch<='9')
        sum=(sum<<3)+(sum<<1)+ch-'0';
    return sum*sign;
}
int main(){
    t=fr();
    while(t--){
        s=fr(); n=fr();
        printf("%d %d\n",s,n+1>>1);
        priority_queue<int,vector<int>,greater<int> >q1;
        priority_queue<int,vector<int>,less<int> >q2;
        x=fr();
        printf("%d ",x);
        q1.push(x);
        for(int i=2;i<=n;i++){
            x=fr();
            if(q1.top()>=x)
                q2.push(x);
            else
                q1.push(x);
            if(q1.size()>q2.size()+1){
                q2.push(q1.top());
                q1.pop();
            }
            else if(q1.size()+1<q2.size()){
                q1.push(q2.top());
                q2.pop();
            }
            if(i%2==1){
                if(q1.size()>q2.size())
                    printf("%d ",q1.top());
                else
                    printf("%d ",q2.top());
            }
            if(i%20==0)
                printf("\n");
        }
        printf("\n");
    }
    return 0;
}