題目鏈接
https://www.acwing.com/problem/content/108/
依次讀入一個整數序列,每當已經讀入的整數個數爲奇數時,輸出已讀入的整數構成的序列的中位數。
輸入格式
第一行輸入一個整數P,代表後面數據集的個數,接下來若干行輸入各個數據集。
每個數據集的第一行首先輸入一個代表數據集的編號的整數。
然後輸入一個整數MM,代表數據集中包含數據的個數,MM一定爲奇數,數據之間用空格隔開。
數據集的剩餘行由數據集的數據構成,每行包含10個數據,最後一行數據量可能少於10個,數據之間用空格隔開。
輸出格式
對於每個數據集,第一行輸出兩個整數,分別代表數據集的編號以及輸出中位數的個數(應爲數據個數加一的二分之一),數據之間用空格隔開。
數據集的剩餘行由輸出的中位數構成,每行包含10個數據,最後一行數據量可能少於10個,數據之間用空格隔開。
輸出中不應該存在空行。
數據範圍
1≤P≤1000
1≤M≤9999
輸入樣例:
3
1 9
1 2 3 4 5 6 7 8 9
2 9
9 8 7 6 5 4 3 2 1
3 23
23 41 13 22 -3 24 -31 -11 -8 -7
3 5 103 211 -311 -45 -67 -73 -81 -99
-33 24 56
輸出樣例:
1 5
1 2 3 4 5
2 5
9 8 7 6 5
3 12
23 23 22 22 13 3 5 5 3 -3
-7 -3
題解
爲了動態維護中位數,我們可以建立兩個二叉堆:一個小根堆,一個大根堆。再依次讀入這個整數序列的過程中,設當前序列長度爲M,我們始終保持:
1.序列從小到大排名爲1到M/2的整數保存在大根堆裏;
2.序列從小到大排名在M/2+1到M的整數保存在小根堆裏
任何時候,如果某一個堆中元素過多,打破這個性質,就取出該堆的堆頂插入另一個堆。這樣一來,序列的中位數就是小根堆的堆頂。
每次讀入一個數值X後,或X比中位數小,則插入到大根堆中,否則插入小根堆中,在插入之後檢查並維護上述性質即可。這就是“”對頂堆”算法。
代碼
#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=1e6+5;
int main(){
int t;
cin>>t;
while(t--){
priority_queue<int> maxx;
priority_queue<int,vector<int>,greater<int> > minn;
int x,y;
cin>>x>>y;
cout<<x<<" "<<(y+1)/2<<endl;
int cnt=0;
for(int i=0;i<y;i++){
int a;
cin>>a;
if(minn.empty()||minn.top()<a){
minn.push(a);
if(minn.size()>maxx.size()+1){
int b=minn.top();
minn.pop();
maxx.push(b);
}
}else{
maxx.push(a);
if(maxx.size()>minn.size()){
int b=maxx.top();
maxx.pop();
minn.push(b);
}
}
if(i%2==0){
cout<<minn.top()<<" ";
cnt++;
}
if(cnt==10){
cnt=0;
cout<<endl;
}
}
if(cnt!=0) cout<<endl;
}
return 0;
}