3871 中位数
这个题做了一个中午了,还是不会,我服气了
维护中位数,就得利用对顶堆来解决,对顶堆就是维护两个堆,从而进行解决我们想要的问题
因为说到中位数,需要我们所操作的序列必须要进行一个排序
利用一个大根堆一个小根堆,小根堆放n/2个元素,大根堆放n-n/2个元素
前半段存大根堆,后半段存小根堆,所以大根堆的堆顶就是中位数
基本上做了一天了,终于悟出来了,真的很水
这里运用的是一个叫做对顶堆的操作,再加上优先队列的黑科技骚操作,这里需要在纸上模拟一下这个操作,预处理两个堆,一个大根堆一个小根堆,从中间进行分开,前半段大根堆,后半段小根堆(这里使用算中间点的方法是mid=(n+1)/2,这样做是为了确保奇数情况从而向上取整)
这样预处理的时候,我们不断地将新来的数对当前中位数进行比较,判断需要插入的地方,是大根堆还是小根堆
还需要思考一个问题,就是更新大根堆堆顶的元素,不断的地插入的过程中,会使一些中位数失去中位数的地位,重新的进行维护,删去大根堆堆顶元素然后插入小根堆,达到重新维护中位数的目的
那么什么时候重新维护中位数呢?对于大根堆,就是超出小根堆两个元素的时候,因为就不满足中位数的性质了;对于小根堆,如果大于大根堆就不,满足了,因为想一下,中位数分开的两个区间,只能相等或者右差左一,不能右区间大,所以不满足了中位数的性质了,需要更新
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<queue>
using namespace std;
const int SIZE=1e5+5;
int arr[SIZE];
priority_queue<int> qb;//大根堆
priority_queue<int,vector<int>,greater<int> > qs;//小根堆
int n,m;
string opt;
int k;
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
cin>>arr[i];
sort(arr+1,arr+n+1);
int mid=(n+1)/2;//加一确保奇数向上取整
for(int i=1;i<=mid;i++)
{
qb.push(arr[i]);
}
for(int i=mid+1;i<=n;i++)
{
qs.push(arr[i]);
}
//前半段大根堆,后半段小根堆
cin>>m;
while(m--)
{
cin>>opt;
if(opt[0]=='m')//模拟指令
cout<<qb.top()<<"\n";
else//模拟指令
{
cin>>k;
int temp=qb.top();
if(k<temp)
{
qb.push(k);
if(qb.size()-qs.size()==2)
{
int l=qb.top();
qb.pop();
qs.push(l);
//这个操作就是说,插入的数超了的话需要重新维护中位数
}
}
else
{
qs.push(k);
if(qs.size()>qb.size())
{
int l=qs.top();
qs.pop();
qb.push(l);
}
}
}
}
return 0;
}