洛谷题单指南-二叉堆与树状数组-P1168 中位数

原题链接:https://www.luogu.com.cn/problem/P1168

题意解读:中位数就是位于中间的数,前1个数的中位数是第1个,前3个数的中位数是第2个,前5个数的中位数的第3个...以此类推。

所以,此题本质上就是动态维护一组数,每1/3/5...等奇数个取第k小的数,取一次后k++。

解题思路:

要动态维护数据,且每次取第k小的数,又有多种做法:快选、平衡树、双堆,这里依然采用双堆做法:

定义一个小根堆,一个大根堆,确保小根堆的堆顶大于大根堆的堆顶,大根堆的元素个数保持在k-1个,这样每次取小根堆的堆顶即是第k小的数。

本题和P1801 黑匣子本质上是一样的。

100分代码:

#include <bits/stdc++.h>
using namespace std;

const int N = 100005;
int n, a;
priority_queue<int> q1; //大根堆
priority_queue<int, vector<int>, greater<int>> q2; //小根堆
int cnt;

int main()
{
    cin >> n;
    for(int i = 1; i <= n; i++)
    {
        cin >> a;
        q1.push(a);
        if(q1.size() > cnt) //如果大根堆超过cnt个
        {
            q2.push(q1.top()); //将大根堆堆顶移至小根堆
            q1.pop();
        }

        if(i % 2 == 1) //每奇数个
        {
            cout << q2.top() << endl; //输出第cnt+1小的值
            cnt++; //cnt下次+1

            if(q1.size() < cnt) //如果大根堆不足cnt个
            {
                q1.push(q2.top()); //将小根堆堆顶移至大根堆
                q2.pop();
            }
        }
    }
    return 0;
}

 

posted @ 2024-11-08 17:27  五月江城  阅读(7)  评论(0编辑  收藏  举报