·今天考試這題因為小數點問題少了三十分,一開始這題用的暴力做的(就是為了騙分還沒騙到┏┛墓┗┓),好吧wsl
·題目內容:
1.Background
雖然CZR數學很爛,但是他還是想證明一下自己的數學能力,今天他
想要表演一下瞬間計算中位數.
2.Description
一開始集合為空,每次有兩個操作:
1 x:告訴CZR當前集合中再加入一個數x.
2 :詢問CZR當前集合的中位數是多少.
·題目來源:山東濟南集訓2019.8考試題二的第三題
·算法:堆頂堆
·算法實現輔助:STL
·算法介紹:
使用兩個堆,大根堆維護較小的值,小根堆維護較大的值
即小根堆的堆頂是較大的數中最小的,大根堆的堆頂是較小的數中最大的
將大於大根堆堆頂的數(比所有大根堆中的元素都大)的數放入小根堆,小於等於大根堆堆頂的數(比所有小根堆中的元素都小)的數放入大根堆
那么就保證了所有大根堆中的元素都小於小根堆中的元素
於是我們發現對於大根堆的堆頂元素,有【小根堆的元素個數】個元素比該元素大,【大根堆的元素個數-1】個元素比該元素小;
同理,對於小跟堆的堆頂元素,有【大根堆的元素個數】個元素比該元素小,【小根堆的元素個數-1】個元素比該元素大;
那么維護【大根堆的元素個數】和【小根堆的元素個數】差值不大於1之后,元素個數較多的堆的堆頂元素即為當前中位數;(如果元素個數相同,那么就是兩個堆堆頂元素的平均數,本題不會出現這種情況)
根據這兩個堆的定義,維護方式也很簡單,把元素個數多的堆的堆頂元素取出,放入元素個數少的堆即可。

·本題思路:
只要維護兩個堆:
一個大根堆,保存的是集合中小的一半的數字;
一個小根堆,保存的是集合中大的一半的數字.
這樣子每次加一個數就只要保持堆的大小差距在1之內就可以了.
中位數就是某一個堆頂或者兩個堆頂的中位數.
·板子:
#include <cstdio>
#include <queue>
using namespace std;
priority_queue <int, vector<int>, less<int> > mnh;
priority_queue <int, vector<int>, greater<int> > mxh;
inline void insert_mx(int x) {
mxh.push(x);
}
inline void insert_mn(int x) {
mnh.push(x);
}
inline int pop_mx() {
int tmp = mxh.top();
mxh.pop();
return tmp;
}
inline int pop_mn() {
int tmp = mnh.top();
mnh.pop();
return tmp;
}
int T;
int op, x;
int ans;
int tot_size;
int main() {
//freopen("mid.in", "r", stdin);
//freopen("mid.out", "w", stdout);
scanf("%d\n", &T);
while (T--) {
scanf("%d", &op);
if (op == 1) {
++tot_size;
scanf("%d", &x);
insert_mx(x);
while (mxh.size() && mnh.size() && mnh.top() > mxh.top()) {
x = pop_mx(), insert_mn(x);
x = pop_mn(), insert_mx(x);
}
//將大於大根堆堆頂的數(比所有大根堆中的元素都大)的數放入小根堆,
//小於等於大根堆堆頂的數(比所有小根堆中的元素都小)的數放入大根堆。
while (mxh.size() > (tot_size / 2))
x = pop_mx(), insert_mn(x);
while (mxh.size() < (tot_size / 2))
x = pop_mn(), insert_mx(x);
//保證大根堆大小等於總大小一半.
//小根堆大小≤大根堆大小+1&&小根堆大小≥大根堆大小
//想法原因:對於大根堆的堆頂元素,
//有【小根堆的元素個數】個元素比該元素大,
//【大根堆的元素個數-1】個元素比該元素小;
}
if (op == 2) {
if (tot_size % 2 == 1) {
printf("%d\n", mnh.top());
} else {
ans = mnh.top() + mxh.top();
if (ans % 2 == 1)
printf("%d.5\n", ans >> 1);
else
printf("%d\n", ans >> 1);
}
}
}
//fclose(stdin);
//fclose(stdout);
return 0;
}
