1. 程式人生 > >中位數 (優先佇列)

中位數 (優先佇列)

中位數

這種題型比較常見,所以總結下來為妙。

一般暴力的方法是找到排一個序,然後輸出中間點。
然後正解的方法是優先佇列。

解法

一個大根堆一個小根堆,用於儲存中位數左邊的數和中位數右邊的數。
然後每一次插入某個數的時候,可以插入到中間,然後判斷左右兩個堆的大小,保持均等即可。

#include <iostream>
#include <queue>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std;
void read(int &x) {
    int f=1;
    x=0;
    char s=getchar();
    while(s<'0'||s>'9') {
        if(s=='-') f=-1;
        s=getchar();
    }
    while(s>='0'&&s<='9') {
        x=x*10+s-'0';
        s=getchar();
    }
    x*=f;
}
int n,m;
int a[200000];
string mid="mid";
string add="add";
priority_queue<int,vector<int>,less<int> >B;
priority_queue<int,vector<int>,greater<int> >S;
int main() {
    read(n);
    for(int i=1; i<=n; i++) read(a[i]);
    sort(a+1,a+1+n);
    for(int i=1; i<=n/2; i++)
        B.push(a[i]);
    for(int i=n/2+1; i<=n; i++)
        S.push(a[i]);
    read(m);
    while(m--) {
        string s;
        cin >> s;
        if(s==add) {
            int opt;
            read(opt);
            if(opt>B.top())
                S.push(opt);
            else if(opt<S.top()) B.push(opt);
            int tb=B.size(),ts=S.size();
            while(tb-ts>=2) {
                int u=B.top();
                B.pop();
                S.push(u);
                tb=B.size(),ts=S.size();
            }
            while(ts-tb>=2) {
                int u=S.top();
                S.pop();
                B.push(u);
                tb=B.size(),ts=S.size();
            }
        }
        if(s==mid) {
            if(B.size()>=S.size()) printf("%d\n",B.top());
            else printf("%d\n",S.top());
        }
    }
    return 0;
}

例題

3871 中位數