[TJOI2010] 中位数
题目描述
给定一个由 个元素组成的整数序列,现在有两种操作:
- :在该序列的最后添加一个整数 ,组成长度为 的整数序列。
- :输出当前序列的中位数。
中位数是指将一个序列按照从小到大排序后处在中间位置的数。(若序列长度为偶数,则指处在中间位置的两个数中较小的那个)
例 : 中位数为 。
例 : 中位数为 。
例 : 中位数为 。
输入格式
第一行为初始序列长度 。第二行为 个整数,表示整数序列,数字之间用空格分隔。第三行为操作数 ,即要进行 次操作。下面为 行,每行输入格式如题意所述。
输出格式
对于每个 操作输出中位数的值。
样例 #1
样例输入 #1
6
1 2 13 14 15 16
5
add 5
add 3
mid
add 20
mid
样例输出 #1
5
13
提示
数据范围及约定
- 对于 的数据,,。
- 对于 的数据,,。
序列中整数的绝对值不超过 ,序列中的数可能有重复。
思路
中位数是指在一个数列中,如果将这个数列按照从小到大排序,那么位于数列中间位置的数就是这个数列的中位数。对于有偶数个元素的数列,通常的定义是取中间两个数的平均值作为中位数,但在这段代码中,中位数被定义为中间两个数中的较小者。
这个数据结构使用了两个优先队列,一个是最大堆,一个是最小堆。最大堆存储的是数列中较小的一半的数,最小堆存储的是数列中较大的一半的数。这样,最大堆的堆顶就是数列中的中位数。
在插入一个新的数时,首先判断这个数是否小于最小堆的堆顶,如果是,那么就把这个数插入到最大堆中,否则就插入到最小堆中。然后,如果最小堆的大小超过了最大堆,就把最小堆的堆顶元素移动到最大堆中。如果最大堆的大小超过了最小堆的大小加一,就把最大堆的堆顶元素移动到最小堆中。这样可以保证最大堆和最小堆的大小差距不超过一,从而保证最大堆的堆顶是中位数。
在主函数中,首先读入一个整数n,然后读入n个整数并插入到数据结构中。然后读入一个整数m,接着进行m次操作。每次操作是一个字符串,如果字符串是"add",那么就读入一个整数并插入到数据结构中,否则就输出当前的中位数。
AC代码
#include <iostream>
#include <queue>
#define AUTHOR "HEX9CF"
using namespace std;
int n, m;
int cnt = 0;
priority_queue<int> hmax;
priority_queue<int, vector<int>, greater<int>> hmin;
void push(int x) {
if (!hmin.empty() && x < hmin.top()) {
hmax.push(x);
} else {
hmin.push(x);
}
cnt++;
while (hmin.size() > hmax.size()) {
hmax.push(hmin.top());
hmin.pop();
}
while (hmax.size() > hmin.size() + 1) {
hmin.push(hmax.top());
hmax.pop();
}
}
int main() {
cin >> n;
for (int i = 1; i <= n; i++) {
int t;
cin >> t;
push(t);
}
cin >> m;
for (int i = 1; i <= m; i++) {
string op;
cin >> op;
if (op == "add") {
int t;
cin >> t;
push(t);
} else {
cout << hmax.top() << endl;
}
}
return 0;
}