[洛谷P1168]中位数

题目大意:给你n个数,问你前1、3、5...个数的中位数是多少。

解题思路:首先,前一个数的中位数一定是第一个数。

之后,每次都会读进两个数。

我们需要做到,如果两个数都小于原来的中位数,那么现在的中位数变成比它小的最大的数。

反之,如果两个数都大于等于原来的中位数,则变成比它大的最小的数。

如果一个小,一个大于等于,则显然中位数不变。

可以想到用一个大根堆保存“比当前中位数小的数”,用一个小根堆保存“大于等于当前中位数的数”,

然后,对于读进来的两个数,把比当前中位数小的放进大根堆里,大于等于当前中位数的放进小根堆里。

如果两个数都小于当前中位数,则把当前中位数放进小根堆里(因为答案变小了),然后当前中位数变为大根堆顶,大根堆顶弹出。

反之则把当前中位数放进大根堆里(因为答案变大了),然后当前中位数变为小根堆顶,小根堆顶弹出。

如果一个大一个小于等于,则中位数不变。

时间复杂度$O(nlog_2 n)$。

C++ Code:

#include<cstdio>
#include<queue>
#include<cctype>
std::priority_queue<int,std::vector<int>,std::greater<int> >small;
std::priority_queue<int>big;
int now,n;
inline int readint(){
	char c=getchar();
	for(;!isdigit(c);c=getchar());
	int d=0;
	for(;isdigit(c);c=getchar())
	d=(d<<3)+(d<<1)+(c^'0');
	return d;
}
int main(){
	n=readint();
	printf("%d
",now=readint());
	for(int i=(n-1)>>1;i;--i){
		int a=readint(),p=0;
		if(a<now)--p,big.push(a);else ++p,small.push(a);
		a=readint();
		if(a<now)--p,big.push(a);else ++p,small.push(a);
		if(p<0){
			small.push(now);
			now=big.top();
			big.pop();
		}else
		if(p>0){
			big.push(now);
			now=small.top();
			small.pop();
		}
		printf("%d
",now);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/Mrsrz/p/8017837.html