中位数求法比较多 离线的我不会
比较容易实现的就是 在线的对顶堆
对顶堆的定义:
- 小顶堆存 大于小顶堆堆顶 的 所有元素
- 大顶堆存 小于大顶堆堆顶 的 所有元素
那么 小顶堆和大顶堆堆顶 就是整个 当前数据元素 的 分界线
并且 堆顶对换/互相插入 不影响定义性质
那么当求中位数时 只需调堆即可
得益于堆的性质 每次调堆时间复杂度为log(n)
1. 当前总元素量为奇数时
只要保证 大顶堆元素比小顶堆元素多一 则中位数为大顶堆堆鼎
同理 只要保证 小顶堆元素比大顶堆元素多一 则中位数为小顶堆堆顶
2.当前总元素量为偶数时
只要保证大顶堆元素等于小顶堆 则中位数为(大顶堆顶 + 小顶堆顶) / 2.0
例题及代码
/*
Zeolim - An AC a day keeps the bug away
*/
//pragma GCC optimize(2)
#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <string>
#include <cstring>
#include <algorithm>
#include <stack>
#include <queue>
#include <set>
#include <sstream>
#include <map>
#include <ctime>
#include <vector>
#include <fstream>
#include <list>
#include <iomanip>
#include <numeric>
using namespace std;
using namespace std;
typedef long long ll;
const int MAXN = 1e6 + 7;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
priority_queue <ll, vector<ll>, greater<ll> > smalp;
priority_queue <ll> bigp;
vector <ll> ans;
int len;
cin >> len;
for(int i = 1, x; i <= len; i++)
{
cin >> x;
if(i == 1) //不需求中位数时只需按定义插堆即可
smalp.push(x);
else if(x > smalp.top())
smalp.push(x);
else
bigp.push(x);
if(i & 1) //当需要求中位数时调堆
{
if(smalp.size() > bigp.size())
while(smalp.size() != bigp.size() + 1)
bigp.push(smalp.top()), smalp.pop();
else
while(smalp.size() != bigp.size() + 1)
smalp.push(bigp.top()), bigp.pop();
ans.push_back(smalp.top());
}
}
for(int i = 0; i < ans.size(); i++)
{
cout<<ans[i]<<'\n';
}
return 0;
}