P1168 中位数 (优先队列,巧解)
题目描述
给出一个长度为N的非负整数序列A[i],对于所有1 ≤ k ≤ (N + 1) / 2,输出A[1], A[3], …, A[2k - 1]的中位数。即前1,3,5,……个数的中位数。
输入输出格式
输入格式:
输入文件median.in的第1行为一个正整数N,表示了序列长度。
第2行包含N个非负整数A[i] (A[i] ≤ 10^9)。
输出格式:
输出文件median.out包含(N + 1) / 2行,第i行为A[1], A[3], …, A[2i – 1]的中位数。
输入输出样例
说明
对于20%的数据,N ≤ 100;
对于40%的数据,N ≤ 3000;
对于100%的数据,N ≤ 100000.
Solution
看到是中位数,一开始想用线段树做,结果发现一点都不好处理.
于是看到别人的思路,蛮巧妙的.
1) 首先,既然是中位数,我们想一想,可不可以在维护的时候把它们这些元素就分成两半呢?
一半存小一点的,一半存大一点的.
2) 既然是要这样存数,那么我们可以直接用一个大根堆和一个小根堆来维护.
3) 然后还有就是,我们需要保证这两个堆的元素个数相差1,这样直接让元素多的那个堆的堆顶输出即可.
然后我直接用的STL 里面的堆.
代码
#include<bits/stdc++.h> using namespace std; const int maxn=100008; int c[maxn],n; priority_queue <int,vector<int> > q2; priority_queue <int,vector<int>,greater<int> > q1; int main() { scanf("%d",&n); scanf("%d",&c[1]); if(n%2==0)n--; //如果是偶数,我最后一个没必要处理. cout<<c[1]<<endl; q2.push(c[1]); for(int i=2;i<=n;i+=2) { int x,y; scanf("%d%d",&x,&y); if(x>y) swap(x,y); //保证小一点的数放入大根堆,大一点的放入小根堆. q2.push(x); q1.push(y); if(q2.top()>q1.top()) { int a=q2.top(),b=q1.top(); q2.pop(); q2.push(b); q1.pop(); q1.push(a); } //最后每次要保证输出q2的top,让操作更加简单. cout<<q2.top()<<endl; } return 0; }