[洛谷P1168]中位数

题目大意:给你n个数,要求输出其中前1,3,……,2k-1个数的中位数
题解:第一个中位数是第一个数,每次读两个数,若一小一个大,那么不变;若大大,中位数变成比他小的最大数;反之,中位数变成比他大的最小数。然后可以用一个大根堆和一个小根堆维护(代码中small为比现中位数小的数,即大根堆;big为比现中位数大的数,即小根堆)
卡点:我天真的以为n都为奇(其实一个都不是)

C++ Code:

#include<cstdio>
using namespace std;
const int maxn=100100;
int n,ans,a,b,l;
int s[maxn],small[maxn],big[maxn];
int min(int a,int b){return a<b?a:b;}
int max(int a,int b){return a>b?a:b;}
void swap(int &a,int &b){a^=b^=a^=b;}
void add_small(int x){
	small[l=++small[0]]=x;
	while (l>>1){
		if (small[l>>1]<small[l]){
			swap(small[l>>1],small[l]);
			l>>=1;
		}else break;
	}
}
int pop_small(){
	int xx=small[1];
	small[l=1]=small[small[0]--];
	while ((l<<1)<=small[0]){
		int t=l;
		if(small[l]<small[l<<1])t=l<<1;
		if ((l<<1)<small[0])if(small[t]<small[l<<1|1])t=l<<1|1;
		if (t==l)break;
		swap(small[l],small[t]);
		l=t;
	}
	return xx;
}
void add_big(int x){
	big[l=++big[0]]=x;
	while (l>>1){
		if (big[l>>1]>big[l]){
			swap(big[l>>1],big[l]);
			l>>=1;
		}else break;
	}
}
int pop_big(){
	int xx=big[1];
	big[l=1]=big[big[0]--];
	while ((l<<1)<=big[0]){
		int t=l;
		if(big[l]>big[l<<1])t=l<<1;
		if ((l<<1)<big[0])if(big[t]>big[l<<1|1])t=l<<1|1;
		if (t==l)break;
		swap(big[l],big[t]);
		l=t;
	}
	return xx;
}
int main(){
	scanf("%d",&n);
	scanf("%d",&ans);
	printf("%d
",ans);
	for (int i=0;i<(n-1>>1);i++){
		scanf("%d%d",&a,&b);
		if (a<ans&&b<ans){
			add_small(a);add_small(b);
			add_big(ans);
			ans=pop_small();
			printf("%d
",ans);
			continue;
		}
		if (a>ans&&b>ans){
			add_big(a);add_big(b);
			add_small(ans);
			ans=pop_big();
			printf("%d
",ans);
			continue;
		}
		if ((a>=ans&&b<=ans)||(a<=ans&&b>=ans)){
			add_small(min(a,b));
			add_big(max(a,b));
			printf("%d
",ans);
		}
	}
	return 0;
}
原文地址:https://www.cnblogs.com/Memory-of-winter/p/8017978.html