luogu_1168: 中位数

洛谷1168:中位数(对顶堆)

题目描述:

  • 给定一个长度为\(N\)的非负整数序列\(A_i\),对于所有\((1\leq k\leq\frac{N+1}{2})\),输出\(A_1,A_3,...,A_{2k-1}\)的中位数。即前\(1,3,4,...\)个数的中位数。

输入格式:

  • 第一行为一个整数\(N\),表示序列长度
  • 第二行输入\(N\)个非负整数\(A_i\)\((A_i\leq10^9)\)

输出格式:

  • \(\frac{N+2}{2}\)行,其中第\(i\)行为\(A_1,A_2,A_3,...,A_{2k-1}\)的中位数。

思路:

  • 对顶堆:处理动态中位数等问题,灵活地运用了堆的性质,本质上是维护两个堆。
    • 大根堆\(Q_1\):维护集合中较小值的部分。
    • 小根堆\(Q_2\):维护集合中较大值的部分。
    • 可以知道其中大根堆的所有元素都小于小根堆。
  • 插入操作:
    • 当需要插入的数字\(x\)大于大根堆堆顶时,插入小根堆。
    • 否则插入大根堆。
  • 维护操作:
    • 当两个堆的大小之差的绝对值大于\(1\)时。
    • 如果大根堆的\(size\)大于小根堆的\(size\),则将大根堆的堆顶插入小根堆并让大根堆执行\(pop\)操作。
    • 否则小根堆的堆顶插入大根堆并让小根堆执行\(pop\)操作。
  • 输出结果:
    • 当我遍历到的数字是奇数时,输出\(size\)较大的堆的堆顶。

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
int x, n;
priority_queue<int> q1; //大根堆
priority_queue<int, vector<int>, greater<int> > q2; //小根堆
int main()
{
    scanf("%d%d", &n, &x);
    q1.push(x); //初始值插入大根堆中
    printf("%d\n", x);
    for(int i = 2; i <= n; i++)
    {
        scanf("%d", &x);

        //插入操作
        if(x > q1.top()) q2.push(x);
        else q1.push(x);

        //维护操作
        while(abs((int)q1.size() - (int)q2.size()) > 1)
        {
            if(q1.size() > q2.size())
            {
                q2.push(q1.top());
                q1.pop();
            }
            else
            {
                q1.push(q2.top());
                q2.pop();
            }
        }

        //输出结果
        if(i&1) printf("%d\n", q1.size() > q2.size() ? q1.top() : q2.top());
    }
    return 0;
}

posted @ 2019-10-08 01:11  zhaoxiaoyun  阅读(126)  评论(0编辑  收藏  举报