题解:洛谷 P3378 堆

【题目来源】

洛谷: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

【核心思想】

  1. 问题分析:维护一个动态变化的整数集合,支持三种操作:插入一个元素、查询当前集合中的最小值、删除当前集合中的最小值(若有多个则只删除一个)。这是优先队列(堆) 的经典应用场景,需要高效地支持插入、获取最小值和删除最小值操作。由于操作次数 \(n\) 可能较大(通常 \(10^5\) 级别),每次操作需在对数时间内完成。

  2. 算法选择

    • 二叉堆(小根堆):使用数组模拟完全二叉树,维护堆性质——任意节点的值不大于其子节点(小根堆)。插入元素时放在末尾并向上调整(上浮),删除最小值时移除堆顶并用最后一个元素替代后向下调整(下沉)。每次操作时间复杂度 \(O(\log n)\)
    • C++ STL priority_queue:直接使用标准库提供的优先队列,默认为大根堆,通过 greater<int> 可得到小根堆,代码简洁且可靠。
  3. 关键步骤

    • 读入操作次数 \(n\)
    • 初始化小根堆priority_queue<int, vector<int>, greater<int>> q;
    • 循环处理每条操作
      • 操作 1:读入 \(x\),执行 q.push(x)
      • 操作 2:输出堆顶元素 q.top()(最小值)。
      • 操作 3:执行 q.pop(),删除堆顶元素。
    • 注意:操作 2 和操作 3 前应确保堆非空(题目保证有效操作)。
  4. 时间/空间复杂度

    • 时间复杂度:\(O(n \log n)\),每次堆操作 \(O(\log n)\)
    • 空间复杂度:\(O(n)\),存储堆中元素。
  5. 堆(优先队列)的核心思想

    • 完全二叉树结构:堆是一棵完全二叉树,使用数组存储,父子节点通过下标关系快速定位(左子节点 \(2i\),右子节点 \(2i+1\))。
    • 堆性质维护:插入和删除后通过向上/向下调整,保证根节点始终为最小值,从而 \(O(1)\) 获取最值。
    • 堆排序衍生:堆结构支持动态插入删除,适用于实时获取最值的场景,是优先队列的底层实现。
    • 适用场景:任务调度、Dijkstra 算法、动态中位数等需要频繁提取最值的问题。

【算法标签】

普及 #堆排序

【代码详解】

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

int n;  // 操作次数
priority_queue<int, vector<int>, greater<int>> q;  // 小根堆(最小值优先)

int main()
{
    // 输入操作次数
    cin >> n;

    // 处理每个操作
    for (int i = 1; i <= n; i++)
    {
        int op, x;
        cin >> op;  // 输入操作类型

        if (op == 1)  // 操作1:插入元素
        {
            cin >> x;
            q.push(x);  // 将x插入堆中
        }
        else if (op == 2)  // 操作2:查询最小值
        {
            cout << q.top() << endl;  // 输出堆顶元素(最小值)
        }
        else if (op == 3)  // 操作3:删除最小值
        {
            q.pop();  // 删除堆顶元素(最小值)
        }
    }

    return 0;
}

【运行结果】

5
1 2
1 5
2
2
3
2
5
posted @ 2026-09-02 22:18  团爸讲算法  阅读(14)  评论(0)    收藏  举报