洛谷 P3378:[模板] 堆 ← 二叉堆

【题目来源】
https://www.luogu.com.cn/problem/P3378

【题目描述】
给定一个数列,初始为空,请支持下面三种操作:
1. 给定一个整数 x,请将 x 加入到数列中。
2. 输出数列中最小的数。
3. 删除数列中最小的数(如果有多个数最小,只删除 1 个)。

【输入格式】
第一行是一个整数,表示操作的次数 n。
接下来 n 行,每行表示一次操作。每行首先有一个整数 op 表示操作类型。
· 若 op=1,则后面有一个整数 x,表示要将 x 加入数列。
· 若 op=2,则表示要求输出数列中的最小数。
· 若 op=3,则表示删除数列中的最小数。如果有多个数最小,只删除 1 个。

【输出格式】
对于每个操作 2,输出一行一个整数表示答案。​​​​​​​

【输入样例】
5
1 2
1 5
2
3
2​​​​​​​

【输出样例】
2
5​​​​​​​

【数据范围】
· 对于 30% 的数据,保证 n≤15。
· 对于 70% 的数据,保证 n≤10^4。
· 对于 100% 的数据,保证 1≤n≤10^6,1≤x<2^31,op∈{1,2,3}。

【算法分析】
● 堆是「抽象思想 / 数据结构」,priority_queue 是「C++ 对堆的封装实现」。
(1)简单而言,priority_queue 是 C++ 对 “堆” 这个数据结构的封装实现,但堆的概念比 priority_queue 更宽泛(比如还有左偏树、二项堆等特殊堆)。
(2)priority_queue 是堆的 “常用款实现”,但堆不仅仅只有 priority_queue 这一种实现。
(3)在需要堆的「高级功能」时,会发现 priority_queue 只是堆的 “子集实现”。例如,priority_queue 只能删除堆顶,无法直接删除中间节点等。

● ​​​​​​​左偏树
(1)左偏树是一种可合并的堆(也叫 “可并堆”),它在普通二叉堆(大根 / 小根堆)的基础上,增加了「快速合并两个堆」的能力,同时保证堆的性质(小根堆:父节点≤子节点;大根堆反之)。普通二叉堆合并两个堆的时间复杂度是 O(n),而左偏树能做到 O(logn),这是它的核心优势。
(2)STL 未提供左偏树的实现,必须手动实现(指针 / 结构体 + 递归)。

● 为什么大家常说 “priority_queue 就是堆”?
在 C++ 日常开发 / 算法题中,99% 的场景只需要普通二叉堆(大根 / 小根堆),而 priority_queue刚好完美封装了普通二叉堆的所有核心操作。
(1)小根堆:priority_queue<int,vector<int>,greater<int>> pq;
(2)大根堆:priority_queue<int> pq;

【算法代码】

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

priority_queue<int,vector<int>,greater<int>> q;

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);

    int n,op,x;
    cin>>n;
    while(n--) {
        cin>>op;
        if(op==1) {
            cin>>x;
            q.push(x);
        }
        if(op==2) cout<<q.top()<<endl;
        if(op==3) q.pop();
    }
}

/*
in:
5
1 2
1 5
2
3
2

out:
2
5
*/





【参考文献】
https://www.cnblogs.com/Seren-blingbling/p/19413027
https://www.luogu.com.cn/problem/solution/P3378
https://blog.csdn.net/hnjzsyjyj/article/details/146358448




 

posted @ 2026-02-19 22:53  Triwa  阅读(29)  评论(0)    收藏  举报