比较经典的一道题,以前在洛谷上做到过。
题意:
(原题是英文)
给出n个数字,n为奇数。依次读入这些数字,读入奇数个数的时候,输出当前已输入的数字中的中位数。
注意题目有多组数据。
思路:
算是套路题吧。
我们可以利用两个堆来维护中位数,具体的操作是这样的:
维护一个大顶堆一个小顶堆,接着我们每次维护当前的中位数x,保证大顶堆中的数都小于x,小顶堆中的数都大于等于x。
每次读入2个数,如果这两个数都比x要大,我们放入比x大的小顶堆中。接着我们把x放入大顶堆,从小顶堆中弹出堆顶元素就是新的中位数;
同理,如果这两个数比x要小,我们放入比x小的大顶堆中。接着我们把x放入小顶堆,从大顶堆中弹出堆顶元素作为新的中位数;
如果x介于两数中间,把小数放入大顶堆,大数放入小顶堆,中位数不变。
这样子我们相当于花O(n)扫了一遍读入的数字,每次维护堆中元素需要花费2*logn时间。
总时间复杂度可以认为是O(nlogn)
代码:
#include<bits/stdc++.h> using namespace std; priority_queue<int,vector<int>,greater<int> >q2; //小顶堆 priority_queue<int,vector<int>,less<int> >q1; //大顶堆 int main() { int T; cin>>T; while(T--){ while(!q1.empty())q1.pop(); while(!q2.empty())q2.pop(); int idx,n; scanf("%d%d",&idx,&n); printf("%d %d\n",idx,n/2+1); int x,now,t=0; scanf("%d",&x); t++; now=x; printf("%d ",now); for(int i=1;i<=n/2;i++){ int x,y; scanf("%d%d",&x,&y); t++; if(x>y)swap(x,y); if(x>now){ q1.push(now); q2.push(x); q2.push(y); now=q2.top(); q2.pop(); printf("%d ",now); } else if(y<now){ q2.push(now); q1.push(x); q1.push(y); now=q1.top(); q1.pop(); printf("%d ",now); } else { q1.push(x); q2.push(y); printf("%d ",now); } if(t%10==0)cout<<endl; } if(t%10)cout<<endl; } return 0; }