[TJOI2010] 中位数
题目描述
给定一个由 N N N 个元素组成的整数序列,现在有两种操作:
- 1 add a \texttt{1 add }\textit{a} 1 add a:在该序列的最后添加一个整数 a a a,组成长度为 N + 1 N + 1 N+1 的整数序列。
- 2 mid \texttt{2 mid} 2 mid:输出当前序列的中位数。
中位数是指将一个序列按照从小到大排序后处在中间位置的数。(若序列长度为偶数,则指处在中间位置的两个数中较小的那个)
例
1
1
1:
[
1
,
2
,
13
,
14
,
15
,
16
]
[1, 2, 13, 14, 15, 16]
[1,2,13,14,15,16] 中位数为
13
13
13。
例
2
2
2:
[
1
,
3
,
5
,
7
,
10
,
11
,
17
]
[1, 3, 5, 7, 10, 11, 17]
[1,3,5,7,10,11,17] 中位数为
7
7
7。
例
3
3
3:
[
1
,
1
,
1
,
2
,
3
]
[1, 1, 1, 2, 3]
[1,1,1,2,3] 中位数为
1
1
1。
输入格式
第一行为初始序列长度 N N N。第二行为 N N N 个整数,表示整数序列,数字之间用空格分隔。第三行为操作数 M M M,即要进行 M M M 次操作。下面为 M M M 行,每行输入格式如题意所述。
输出格式
对于每个 mid \verb!mid! mid 操作输出中位数的值。
样例 #1
样例输入 #1
6
1 2 13 14 15 16
5
add 5
add 3
mid
add 20
mid
样例输出 #1
5
13
提示
数据范围及约定
- 对于 30 % 30\% 30% 的数据, 1 ≤ N ≤ 10 , 000 1 ≤ N ≤ 10,000 1≤N≤10,000, 0 ≤ M ≤ 1 , 000 0 ≤ M ≤ 1,000 0≤M≤1,000。
- 对于 100 % 100\% 100% 的数据, 1 ≤ N ≤ 100 , 000 1 ≤ N ≤ 100,000 1≤N≤100,000, 0 ≤ M ≤ 10 , 000 0 ≤ M ≤ 10,000 0≤M≤10,000。
序列中整数的绝对值不超过 1 0 9 10^9 109,序列中的数可能有重复。
思路
中位数是指在一个数列中,如果将这个数列按照从小到大排序,那么位于数列中间位置的数就是这个数列的中位数。对于有偶数个元素的数列,通常的定义是取中间两个数的平均值作为中位数,但在这段代码中,中位数被定义为中间两个数中的较小者。
这个数据结构使用了两个优先队列,一个是最大堆,一个是最小堆。最大堆存储的是数列中较小的一半的数,最小堆存储的是数列中较大的一半的数。这样,最大堆的堆顶就是数列中的中位数。
在插入一个新的数时,首先判断这个数是否小于最小堆的堆顶,如果是,那么就把这个数插入到最大堆中,否则就插入到最小堆中。然后,如果最小堆的大小超过了最大堆,就把最小堆的堆顶元素移动到最大堆中。如果最大堆的大小超过了最小堆的大小加一,就把最大堆的堆顶元素移动到最小堆中。这样可以保证最大堆和最小堆的大小差距不超过一,从而保证最大堆的堆顶是中位数。
在主函数中,首先读入一个整数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;
}