堆——中位数

·今天考试这题因为小数点问题少了三十分,一开始这题用的暴力做的(就是为了骗分还没骗到┏┛墓┗┓),好吧wsl

 

·题目内容

1.Background
虽然CZR数学很烂,但是他还是想证明一下自己的数学能力,今天他
想要表演一下瞬间计算中位数.
2.Description
一开始集合为空,每次有两个操作:
1 x:告诉CZR当前集合中再加入一个数x.
2 :询问CZR当前集合的中位数是多少.
·题目来源:山东济南集训2019.8考试题二的第三题

·算法堆顶堆

·算法实现辅助STL

·算法介绍

使用两个堆,大根堆维护较小的值,小根堆维护较大的值

即小根堆的堆顶是较大的数中最小的,大根堆的堆顶是较小的数中最大的

将大于大根堆堆顶的数(比所有大根堆中的元素都大)的数放入小根堆,小于等于大根堆堆顶的数(比所有小根堆中的元素都小)的数放入大根堆

那么就保证了所有大根堆中的元素都小于小根堆中的元素

于是我们发现对于大根堆的堆顶元素,有【小根堆的元素个数】个元素比该元素大,【大根堆的元素个数-1】个元素比该元素小;

同理,对于小跟堆的堆顶元素,有【大根堆的元素个数】个元素比该元素小,【小根堆的元素个数-1】个元素比该元素大;

那么维护【大根堆的元素个数】和【小根堆的元素个数】差值不大于1之后,元素个数较多的堆的堆顶元素即为当前中位数;(如果元素个数相同,那么就是两个堆堆顶元素的平均数,本题不会出现这种情况)

根据这两个堆的定义,维护方式也很简单,把元素个数多的堆的堆顶元素取出,放入元素个数少的堆即可。

 

·本题思路

只要维护两个堆:
一个大根堆,保存的是集合中小的一半的数字;
一个小根堆,保存的是集合中大的一半的数字.
这样子每次加一个数就只要保持堆的大小差距在1之内就可以了.
中位数就是某一个堆顶或者两个堆顶的中位数.

·板子:

#include <cstdio>
#include <queue>

using namespace std;

priority_queue <int, vector<int>, less<int> > mnh;
priority_queue <int, vector<int>, greater<int> > mxh;

inline void insert_mx(int x) {
	mxh.push(x);
}

inline void insert_mn(int x) {
	mnh.push(x);
}

inline int pop_mx() {
	int tmp = mxh.top();
	mxh.pop();
	return tmp;
}

inline int pop_mn() {
	int tmp = mnh.top();
	mnh.pop();
	return tmp;
}

int T;
int op, x;
int ans;
int tot_size;

int main() {
	//freopen("mid.in", "r", stdin);
	//freopen("mid.out", "w", stdout);
	scanf("%d\n", &T);
	while (T--) {
		scanf("%d", &op);
		if (op == 1) {
			++tot_size;
			scanf("%d", &x);
			insert_mx(x);
			while (mxh.size() && mnh.size() && mnh.top() > mxh.top()) {
				x = pop_mx(), insert_mn(x);
				x = pop_mn(), insert_mx(x);
			}
			//将大于大根堆堆顶的数(比所有大根堆中的元素都大)的数放入小根堆,
			//小于等于大根堆堆顶的数(比所有小根堆中的元素都小)的数放入大根堆。 
			while (mxh.size() > (tot_size / 2))
				x = pop_mx(), insert_mn(x);
			while (mxh.size() < (tot_size / 2))
				x = pop_mn(), insert_mx(x);
				//保证大根堆大小等于总大小一半.
                //小根堆大小≤大根堆大小+1&&小根堆大小≥大根堆大小
                //想法原因:对于大根堆的堆顶元素,
				          //有【小根堆的元素个数】个元素比该元素大,
				          //【大根堆的元素个数-1】个元素比该元素小; 
		}
		if (op == 2) {
			if (tot_size % 2 == 1) {
				printf("%d\n", mnh.top());
			} else {
				ans = mnh.top() + mxh.top();
				if (ans % 2 == 1)
					printf("%d.5\n", ans >> 1);
				else
					printf("%d\n", ans >> 1);
			}
		}
	}
	//fclose(stdin);
	//fclose(stdout);
	return 0;
} 
posted @ 2019-08-21 20:18  Au0702  阅读(712)  评论(3编辑  收藏  举报