版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_27121257/article/details/82855962
传送门:洛谷 P1168
题目描述
给出一个长度为 的非负整数序列 ,对于所有 ,输出 的中位数。即前 个数的中位数。
分析
题目简单明了,就是求中位数,而且保证是个奇数序列。
中位数,即排序后最中间的数。最暴力的解法就是直接
一遍,但是,如果动态的询问,那会显的有点吃力。怎么办呢?(这不是平衡树吗? --某大佬言)
但最近在树上发现了一种更为简单的算法—对顶堆(动态维护序列第
值)
简单的来说就是利用两个堆(一个大根堆,一个小根堆)来维护序列,保证第
值在其中一个堆的堆顶。
就中位数而言:
令大根堆
,小根堆
- 加入一个元素
放入:若 大于 的堆顶元素,则放入 ,否则放入
调整:若 ,将其中一方的堆顶元素放入另一个堆中 - 取两者个数较多的堆顶元素
代码
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>
#define IL inline
using namespace std;
IL int read()
{
char c = getchar();
int sum = 0 ,k = 1;
for(;'0' > c || c > '9'; c = getchar())
if(c == '-') k = -1;
for(;'0' <= c && c <= '9'; c = getchar()) sum = sum * 10 + c - '0';
return sum * k;
}
struct node
{
priority_queue<int>Q1;
priority_queue<int, vector<int>, greater<int> > Q2;
int t1, t2;
IL node()
{
t1 = t2 = 0;
}
IL void add(int x)
{
if(!t1) { ++t1; Q1.push(x); return ; }
if(x > Q1.top()) { Q2.push(x); ++t2; } else { Q1.push(x); ++t1; }
if(t2 - t1 > 1) { Q1.push(Q2.top()); Q2.pop(); --t2; ++t1; } else
if(t1 - t2 > 1) { Q2.push(Q1.top()); Q1.pop(); --t1; ++t2; }
}
IL int get_mid()
{
if(t1 ^ t2) return t1 < t2 ? Q2.top() : Q1.top();
return Q1.top();
}
}a;
int main()
{
int n = read();
for(int i = 1; i <= n; ++i)
{
a.add(read());
if(i & 1) printf("%d\n", a.get_mid());
}
return 0;
}