對頂堆

洛谷 1168 中位數

題目描述

給出一個長度爲NN的非負整數序列A_iAi​,對於所有1≤k≤(N+1)/2,輸出A1​,A3​,…,A2k−1​的中位數。即前1,3,5,…個數的中位數。

輸入格式

第1行爲一個正整數N,表示了序列長度。

第2行包含N個非負整數Ai​(Ai​≤10^9)。

輸出格式

共(N+1)/2行,第i行爲A1​,A3​,…,A2k−1​的中位數。

輸入輸出樣例

輸入 

7
1 3 5 7 9 11 6

輸出 

1
3
5
6

說明/提示

對於20\%20%的數據,N ≤ 100N≤100;

對於40\%40%的數據,N ≤ 3000N≤3000;

對於100\%100%的數據,N ≤ 100000N≤100000。

解析:

使用兩個堆,大根堆維護較小的值,小根堆維護較大的值,即大根堆的堆頂是較小的數中最大的,小根堆的堆頂是較大的數中最小的

將大於大根堆堆頂的數(比所有大根堆中的元素都大)的數放入小根堆,小於等於大根堆堆頂的數(比所有小根堆中的元素都小)的數放入大根堆,那麼就保證了所有大根堆中的元素都小於小根堆中的元素

於是我們發現對於大根堆的堆頂元素,有【小根堆的元素個數】個元素比該元素大,【大根堆的元素個數-1】個元素比該元素小;同理,對於小跟堆的堆頂元素,有【大根堆的元素個數】個元素比該元素小,【小根堆的元素個數-1】個元素比該元素大;

那麼維護【大根堆的元素個數】和【小根堆的元素個數】差值不大於1之後,元素個數較多的堆的堆頂元素即爲當前中位數;(如果元素個數相同,那麼就是兩個堆堆頂元素的平均數,本題不會出現這種情況)

根據這兩個堆的定義,維護方式也很簡單,把元素個數多的堆的堆頂元素取出,放入元素個數少的堆即可

AC代碼:

#include <bits/stdc++.h>
using namespace std;
priority_queue<int,vector<int> >Q1;//大根堆,維護較小的數值
priority_queue<int,vector<int>,greater<int> >Q2;//小根堆,維護較大的數值
int main(){
    int n,x;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&x);
        if(!Q1.empty()&&x<=Q1.top()) Q1.push(x);
        else if(!Q2.empty()&&x>Q2.top()) Q2.push(x);
        else Q2.push(x);
        //調整堆的大小,滿足(小頂堆元素個數)-(大頂堆元素個數)= 1
        if(Q1.size()>Q2.size()){
            Q2.push(Q1.top());
            Q1.pop();
        }
        else if(Q2.size()>Q1.size()+1){
            Q1.push(Q2.top());
            Q2.pop();
        }
        if(i%2==1) printf("%d\n",Q2.top());
    }    
    return 0;
}

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章