[洛谷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\n",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\n",ans);
continue;
}
if (a>ans&&b>ans){
add_big(a);add_big(b);
add_small(ans);
ans=pop_big();
printf("%d\n",ans);
continue;
}
if ((a>=ans&&b<=ans)||(a<=ans&&b>=ans)){
add_small(min(a,b));
add_big(max(a,b));
printf("%d\n",ans);
}
}
return 0;
}

浙公网安备 33010602011771号