【题目描述】
给出一个长度为N的非负整数序列Ai,对于所有1≤k≤(N+1)/2,输出A1, A3, …, A2k-1的中位数。即前1,3,5,…个数的中位数。
n<=100000
【思路】
第一步:考虑求1~n的中位数,把数组排序最中间的数就是答案.
⇒考虑怎么用堆来维护这个答案.
对于一个长为i的序列,(i为奇数.)
记x表示这个序列的中位数,然后我们用大根堆维护前一半小的数,用小根堆维护后一半小的数,这样序列分为了[1,(i-1)/2]∪[(i+1)/2,i](x放在哪一半都可以)
现在考虑加进去一个数w
让w和前一半大根堆的堆顶元素比较,大放入后半部分小根堆中,反之,放到前半部分大根堆中
维护两个堆大小差在1以内,然后输出大小较大的堆顶的元素,就是中位数
【代码】
#include<cstdio>
#include<queue>
#include<cmath>//abs头文件
using namespace std;
priority_queue<int,vector<int> >q1;
priority_queue<int,vector<int>,greater<int> >q2;
int main(){
int n,x;
scanf("%d",&n);
scanf("%d",&x);
q1.push(x);
printf("%d\n",x);
for (int i=2;i<=n;i++){
scanf("%d",&x);
if (x>q1.top()) q2.push(x);//新加入的x放进去
else q1.push(x);
while(abs((int)q1.size()-(int)q2.size())>1){ //维护两个大小差1以内,abs——取绝对值函数
if (q1.size()>q2.size()){
q2.push(q1.top());q1.pop();
}
else{
q1.push(q2.top());q2.pop();
}
}
if(i%2==1) printf("%d\n",q1.size()>q2.size()?q1.top():q2.top());//输出大小大的那个堆的堆定元素
}
return 0;
}
P.S代码实现及评测中的一点小问题,abs在本机可以编译,但是在洛谷上会出现CE情况
这是由于size()函数返回的是无符号整数,所以使用int转换一下即可【卡了很久】