首页 > 其他分享 >【模板】堆 题解

【模板】堆 题解

时间:2023-05-05 22:45:19浏览次数:50  
标签:结点 cur int 题解 cnt swap heap 模板

题目传送门

一道小根堆模板题。

在做这道题之前,我们先介绍一下小根堆是什么。

我们定义小根堆是一种对于任何一个父结点的权值总是小于或等于子节点权值的完全二叉树。因此,不难看出,一个小根堆的堆顶(这棵树的根节点)应该是这个堆(树)中权值最小的结点。

简单介绍完了小根堆,我们再介绍下如何存储。

存储

我们考虑用一个数组进行存储,用一个变量来记录堆里的元素个数。

int heap[1000005]; // 用数组存储
int cnt; // 记录堆中的元素个数,也是下一个元素插入进来的位置

学会了如何存储小根堆,接下来我们要实现几个操作:

  • 插入一个数

  • 查询堆顶

  • 删除堆顶

插入一个数

我们需要在最后一个位置插入,然后从下往上进行维护。如果发现父结点的权值大于子结点的权值,则将子结点父结点进行交换,然后继续往上进行搜索。

void xds(int cur) { 
    int fa = (cur - 1) / 2; // 父亲结点的位置
    if (heap[fa] > heap[cur]) { // 如果不合法
        swap(heap[fa], heap[cur]); // 进行交换
        xds(fa); // 继续往上维护
    }
}
void insert(int x) {
    heap[cnt] = x; // 插入
    xds(cnt++); // 维护
}

查询堆顶

之前说过,堆顶应该是整个堆中最小的元素,而我们插入维护是从下往上进行维护(对于整个数组,我们可以说是从后往前进行维护)的,因此堆顶为 heap[0]


删除堆顶

我们可以将堆顶与最后一个元素进行互换,然后将长度减 \(1\),就相当于删掉了这个元素。之后我们从上往下维护一遍,我们分成没有子结点,有一个子结点,有两个子结点这 \(3\) 种情况进行维护,原理与插入差不多。

void sdx(int cur) {
    if (2 * cur + 1 >= cnt) return ; // 没有子结点
    if (2 * cur + 2 >= cnt) { // 有一个子结点
        if (heap[2 * cur + 1] < heap[cur]) swap(heap[2 * cur + 1], heap[cur]);
        return ;
    }
    int l = 2 * cur + 1, r = l + 1;
    if (heap[l] > heap[r]) swap(l, r); // 确定哪个子结点跟这个结点交换
    if (heap[l] < heap[cur]) { // 不合法
        swap(heap[l], heap[cur]); // 交换
        sdx(l); // 继续往下维护
    }
}
void del() {
    swap(heap[0], heap[--cnt]); // 删掉堆顶
    sdx(0); // 从上往下进行维护
}

Code

#include <bits/stdc++.h>
#define ll long long
#define INF 1e9
using namespace std;
int n;
int heap[1000005]; // 用数组存储
int cnt; // 记录堆中的元素个数,也是下一个元素插入进来的位置
void xds(int cur) { 
    int fa = (cur - 1) / 2; // 父亲结点的位置
    if (heap[fa] > heap[cur]) { // 如果不合法
        swap(heap[fa], heap[cur]); // 进行交换
        xds(fa); // 继续往上维护
    }
}
void insert(int x) {
    heap[cnt] = x; // 插入
    xds(cnt++); // 维护
}
void sdx(int cur) {
    if (2 * cur + 1 >= cnt) return ; // 没有子结点
    if (2 * cur + 2 >= cnt) { // 有一个子结点
        if (heap[2 * cur + 1] < heap[cur]) swap(heap[2 * cur + 1], heap[cur]);
        return ;
    }
    int l = 2 * cur + 1, r = l + 1;
    if (heap[l] > heap[r]) swap(l, r); // 确定哪个子结点跟这个结点交换
    if (heap[l] < heap[cur]) { // 不合法
        swap(heap[l], heap[cur]); // 交换
        sdx(l); // 继续往下维护
    }
}
void del() {
    swap(heap[0], heap[--cnt]); // 删掉堆顶
    sdx(0); // 从上往下进行维护
}
signed main() {
    ios :: sync_with_stdio(0);
    cin >> n;
    for (int i = 1; i <= n; i++) {
        int op;
        cin >> op;
        if (op == 1) {
            int x;
            cin >> x;
            insert(x);
        }
        else if (op == 2) cout << heap[0] << "\n";
        else del();
    }
    return 0;
}

标签:结点,cur,int,题解,cnt,swap,heap,模板
From: https://www.cnblogs.com/xvl-/p/17375591.html

相关文章

  • 【ABC298C】题解
    思路一道很好的复习数据结构的题。对于第\(1\)个问答(既第\(2\)种操作),我用一个小根堆(优先队列,\(\text{priority\_queue}\))来储存第\(i\)个盒子的卡牌。对于第\(2\)个问答(既第\(3\)种操作),我用一个\(\text{set}\)来储存编号为\(i\)个卡牌在哪些盒子里。由于\(\tex......
  • 求最大值(函数模板)
    一、问题描述:两个类如下设计:类Time有三个数据成员,hh,mm,ss,分别代表时,分和秒,并有若干构造函数和一个重载-(减号)的成员函数。类Date有三个数据成员,year,month,day分别代表年月日,并有若干构造函数和一个重载>(<)(大于号或者小于号)的成员函数。要求设计一个函数模板template<classT>Tma......
  • 【学习笔记】【题解】树形依赖 DP 选做
    地址:https://www.cnblogs.com/FReQuenter5156/p/shuxingyilaidp.html/简介这类背包本质上是分组背包问题。将一个节点的每一棵子树看作一组,进行分组背包。所谓分组背包,即在选择物品的时候,一开始将物品分为好几组,在选择时,可以从每一组中至多选择一件物品,问如何获得最大的价值,所......
  • CF338D GCD Table-题解(excrt)
    CF338DGCDTable个人评价:还好算法扩展CRT题面给了一张\(n\timesm\)的矩阵,第i行j列的权值是gcd(i,j),现在有一个长度为k的序列A,问是否存在(i,j)使得\(gcd(i,j+l-1)=a_l(1\leql\leqk)\)问题分析我们将对应行设为x,对应列设为y,那么就有如下同余方程组\(x\equiv(y+l-1)......
  • P8446 虹色的北斗七星 题解
    传送门前言:很久之前做的一道题目了,当时并没有想出来怎么做,随便猜了个结论交上去发现过了。(好像还是第一道自己做出来的绿)简要题意:你有一个长度为\(n\)的序列\(a\),一个区间\([l,r]\)的价值定义为当前区间的极差减去区间长度,求出最大的价值。\(Solution\):看了看题解,发现......
  • eclipse注释模板及格式化模板导入方法
    格式化模板导入步骤  1.点击Window->Preference->Java->CodeStyle->Formatter2.点击右侧Import选择*.xml模板文件导入即可3.如果需要对模板进行修改,可点击Edit编辑即可4.模板示例:1.<?xmlversion="1.0"encoding="UTF-8"standalone="no"?>2.<profilesvers......
  • [CodeForces-545A]题解(C++)
    PartIPreface原题目(Luogu)原题目(CodeForces)PartIISketch给定一个正整数\(n\),表示汽车数量。给定一个\(n\timesn\)阶矩阵\(A\),第\(i\)行\(j\)列上的数字表示\(i\)车与\(j\)车的对撞情况。\(\begin{aligned}\begin{cases}A_{i,j}=-1&i,j\text{车没......
  • [CodeForces-545A]题解(C++)
    PartIPreface原题目(Luogu)原题目(CodeForces)PartIISketch给定一个正整数\(n\),表示汽车数量。给定一个\(n\timesn\)阶矩阵\(A\),第\(i\)行\(j\)列上的数字表示\(i\)车与\(j\)车的对撞情况。\(\begin{aligned}\begin{cases}A_{i,j}=-1&i,j\text{车没......
  • CF1260E Tournament 题解
    妙妙题,但是感觉评不到紫。题目链接。题意luogu题意。有\(n\)个人,贿赂第\(i\)个人的代价为\(a_i\)。这些人中,贿赂代价为\(-1\)的是你的朋友。现在,你可以两两配对,使得编号小的被淘汰,但是,如果你贿赂了编号大的,那么编号大的被淘汰,而编号小的留下。问:使得你朋友夺得冠军的......
  • django迁移数据库错误问题解决
    删除所有的pyc文件,迁移文件然后重新运行python3manage.pymakemigrationsdjango.db.utils.InternalError:(1060,"Duplicatecolumnname'addr_id'")运行python3manage.pymigrate--fake然后重新运行python3manage.pymigrate成功!......