洛谷OJ [P1168 中位数] 对顶堆

发布时间 2023-09-14 00:47:17作者: yanhy-orz

P1168 中位数

对顶堆用于维护序列的第 $ k $ 大元素, 原理是:建立一个小根堆和一个大根堆, 小根堆存储序列的前 $ k $ 大元素, 大根堆存储其他元素; 要取的第 $ k $ 大元素即是小根堆的堆顶, 维护的做法是:在查询之前, 保证小根堆的大小为 $ k $, 若有多余, 将多余部分转移到大根堆中, 否则, 从大根堆转移若干元素, 直到小根堆大小为 $ k $。

思路:对于此题, 当 $ i $ 为奇数时, 需要回答第 $ (i + 1) / 2 $ 大元素, 则, 在此时调整堆的大小即可。

点击查看代码
#include <bits/stdc++.h>
#define sz(a) ((int) (a).size())
using i64 = long long;

inline i64 read() {
    bool sym = false; i64 res = 0; char ch = getchar();
    while (!isdigit(ch)) sym |= (ch == '-'), ch = getchar();
    while (isdigit(ch)) res = (res << 3) + (res << 1) + (ch ^ 48), ch = getchar();
    return sym ? -res : res;
}

int main() {
    int n = read(); std::vector<int> a(n + 1);
    std::priority_queue<int, std::vector<int>, std::greater<int>> qmin;
    std::priority_queue<int, std::vector<int>, std::less<int>> qmax;
    for (int i = 1; i <= n; i++) {
        a[i] = read();
    }
    for (int i = 1; i <= n; i++) {
        if (qmin.empty() || a[i] >= qmin.top()) {
            qmin.push(a[i]);
        } else {
            qmax.push(a[i]);
        }
        if (i & 1) {
            int k = (i + 1) / 2;
            while (qmin.size() > k) {
                qmax.push(qmin.top()); qmin.pop();
            }
            while (qmin.size() < k) {
                qmin.push(qmax.top()); qmax.pop();
            }
            printf("%d\n", qmin.top());
        }
    }
    return 0;
}