题目大意:给你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; }