浅贪 对顶堆

其实这个东西的本质还是特别简单的:就是使用两个priority_queue来维护一下即可。

具体地,我们维护一个小根堆和一个大根堆,这里以查询第 \(k\) 大为例进行讲解(也就是说第 \(k\) 小反着来就可以了):

  1. 既然我们是求第 \(k\) 大,那我们可以用小根堆维护当前的前 \(k\) 大的数值,用大根堆维护剩下的。

  2. 之后就是插入操作(设小根堆的堆顶值为 \(x\),当前插入的数为 \(y\))

    • 如果小根堆为空,或者 \(y\ge x\)

      就将 \(y\) 搞到小根堆里

    • 否则,就将 \(y\) 搞到大根堆里

  3. 如果当前的 \(k\) 变化,那我们就顺势调整大根堆和小根堆

例题

传送门

在这个题目中,我们发现我们需要得到第 \(k\) 小,同时我们还可以发现性质,就是添加一个数,中位数所在的位置只可能不动或者 \(\pm 1\) .

那就做完了:

#include <bits/stdc++.h>
using namespace std;
#define il inline
int n;
priority_queue<int >q1;
priority_queue<int,vector<int>,greater<int> >q2;
il void solve() {
    if(n==-1) {
        cout<<q1.top()<<'\n';q1.pop();
    } else {
        if(q1.size()==0||n<=q1.top())q1.push(n);
        else q2.push(n);
    }int sum=q1.size()+q2.size();
    if(q1.size()<(sum+1)/2) {
        q1.push(q2.top());q2.pop();
    }if(q1.size()>(sum+1)/2) {
        q2.push(q1.top());q1.pop();
    }
}
int main() {
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int T;cin>>T;while(T--) {
        while(q1.size())q1.pop();while(q2.size())q2.pop();
        while(1){cin>>n;if(!n)break;solve();}
    }
    return 0;
}
posted @ 2026-09-17 15:22  tyccyt  阅读(4)  评论(0)    收藏  举报