动态维护中位数(优先队列)

神奇的中位数

Description

中位数:n个数中的中位数为将这n个数从小到大排好序后,第​​\left \lfloor \frac{n+1}{2} \right \rfloor​位数的值。(\left \lfloor x \right \rfloor​为小于等于x​的整数最大的那个)。

现在给定一个空的数组a,然后读入n个数,对于每读入一个数就输出当前数组的中位数是多少。

Input

输入第一行包含一个正整数n(1≤n≤1000000)。

第i+1行包含一个整数x_{i}

对于数组的构造如下:

假定第 i−1次读入后输出的答案是lastans,那么第i次读入加入到数组中的数为x_{i}​⨁lastans,即a_{i}=lastansx_{i}(⨁表示异或,lastans初始为0)。

 为了帮助读懂该构造方法请看样例解释。

数据保证0≤a_{i}≤2×10^{9}

Output

输出包含n行,第i行表示在读入第i个数后当前数组的中位数的值。

Sample Input 1

5 1 2 3 0 1

Sample Output 1

1 1 2 2 2

Hint

优先队列放进去会排好序,默认为大顶堆

//升序队列(小顶堆)
priority_queue <int,vector<int>,greater<int> > q;
//降序队列(大顶堆)
priority_queue <int,vector<int>,less<int> >q;

//greater和less是std实现的两个仿函数(就是使一个类的使用看上去像一个函数。其实现就是类中实现一个operator(),这个类就有了类似函数的行为,就是一个仿函数类了)

实现原理:用大顶堆a装中位数之前的,小顶堆b装中位数之后的,令b的顶部元素为中位数m,每次读入元素时,比m小的就放入a中,大于等于m的就放入b中。当a中元素个数大于b时,将a的堆顶元素弹出作为中位数放入b中,当b.size()-a.size()>2时,即b.size()-a.size()==3时,将b的堆顶元素弹出放入a中,b.top()为新的m.

Plus:当a.size()==b.size()时,中位数在a的顶部!不要漏掉这种情况QWQ

本题代码

#include<stdio.h>
#include<queue>
using namespace std;
priority_queue<int> a;//默认的大顶堆,优先弹出较大的值
priority_queue<int,vector<int>,greater<int>> b; //小顶堆,值较小的元素在上
int n,tp,x,m;
int main(){
	scanf("%d",&n);
	scanf("%d",&m);
	b.push(m);
	printf("%d\n",m);
	for(int i=1;i<n;i++){
		scanf("%d",&x);
		tp=x^m;
		if(tp<m)a.push(tp);
		else b.push(tp);
		if(a.size()>=b.size()){ //注意不要漏掉此处的等号,否则考虑不完整
			m=a.top();
			a.pop();
			b.push(m);
		}
		else if(b.size()-a.size()==3){
			a.push(b.top());
			b.pop();
			m=b.top();
		}
		printf("%d\n",m);
	}
	return 0;
}

  • 7
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值