Loading

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;
}

posted @ 2021-07-14 17:50  Dita  阅读(76)  评论(0编辑  收藏  举报