SP16254 RMID2 - Running Median Again 题解
question
题目大意:
维护一个序列,支持下面两种操作:
- 向序列中插入一个元素
- 输出并删除当前序列的中位数(若序列长度为偶数,则输出较小的中位数)
solution
用 对顶堆 来实现
这个题可以抽象为动态维护一个第 k 大的数,并且 k 值可能在变化。
首先开一个小顶堆和一个大顶堆,小顶堆维护前 k 大的数 (包括第 k 个),大顶堆维护比第 k 大值小的那些数。
这两个堆构成的数据结构支持下面操作:
-
维护:当小根堆的大小小于 k 时,不断将大根堆堆顶元素取出并插入小根堆,直到小根堆的大小等于 k;当小根堆的大小大于 k 时,不断将小根堆堆顶元素取出并插入大根堆,直到小根堆的大小等于 ;
-
插入元素:若插入的元素大于等于小根堆堆顶元素,则将其插入小根堆,否则将其插入大根堆,然后维护对顶堆;
-
查询第 k 大元素:小根堆堆顶元素即为所求;
-
删除第 k 大元素:删除小根堆堆顶元素,然后维护对顶堆;
-
k 值 +1/-1:根据新的 k 值直接维护对顶堆。
时间复杂度:查询 O(1) ,维护 O(log~n)
/*
work by:Ariel_
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
int read() {
int x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9'){if (c == '-') f = -1;c = getchar();}
while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = getchar();}
return x * f;
}
int t, x;
int main(){
t = read();
while (t--) {
priority_queue<int, vector<int>, less<int> > a;
priority_queue<int, vector<int>, greater<int> > b;
while (scanf("%d", &x) && x) {
if (x == -1) {
printf("%d\n", a.top());
a.pop();
}
else {
if (a.empty() || x <= a.top()) a.push(x);
else b.push(x);
}
if(a.size() > (a.size() + b.size() + 1) / 2) b.push(a.top()), a.pop();
else if (a.size() < (a.size() + b.size() + 1) / 2) a.push(b.top()), b.pop();
}
}
puts("");
return 0;
}