洛谷P1168 中位数 题解

洛谷P1168 中位数 题解

题目链接:P1168 中位数

题意

给出一个长度为 N N N的非负整数序列 A i A_i Ai,对于所有 1 ≤ k ≤ ( N + 1 ) / 2 1 ≤ k ≤ (N + 1) / 2 1k(N+1)/2,输出 A 1 , A 1 ∼ A 3 , … , A 1 ∼ A 2 k − 1 A_1, A_1 \sim A_3, …,A_1 \sim A_{2k - 1} A1,A1A3,,A1A2k1的中位数。即前 1 , 3 , 5 , … 1,3,5,… 1,3,5,个数的中位数。

对于 100 % 100\% 100%的数据, N ≤ 100000 N ≤ 100000 N100000

当然可以用vector来搞啦,但是这样就常数大而且没劲了

考虑对顶堆(那篇讲对顶堆的是在绕口令吧。明明很好懂的)

维护两个堆,分别是大根堆和小根堆

有个性质:大根堆q1里的所有值小于小根堆q2里的所有值

然后每次把比q1堆首元素大的元素扔到q2里去,反之塞进q1里

这样还是满足性质的

但是我们要中位数,这就需要q1和q2的size只相差一,才好处理

怎么搞呢,比如q1的size太大了,那我们就把q1的堆首一个个扔到q2里去

这样仍然是满足性质的

注意到每个元素最多入堆2次,因此单次插入操作是 O ( log ⁡ n ) O(\log n) O(logn)

时间复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn)

代码:

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iomanip>
#include <random>
#include <queue>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define N (int)()

int n;
priority_queue<int> q1;
priority_queue<int,vector<int>,greater<int>>q2;
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    cin >> n;
    int x; cin >> x;
    q1.push(x); cout << x << '\n';
    for(int i=2; i<=n; i++)
    {
        cin >> x;
        if(x>q1.top())q2.push(x);
        else q1.push(x);
        while(abs((int)(q1.size()-q2.size()))>1)
        {
            if(q1.size()>q2.size())
                q2.push(q1.top()),q1.pop();
            else q1.push(q2.top()),q2.pop();
        }
        if(i&1) cout << (q1.size()>q2.size()?q1.top():q2.top()) << '\n';
    }
    return 0;
}

转载请说明出处

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值