35.Acwing基础课第839题-简单-模拟堆

35.Acwing基础课第839题-简单-模拟堆

题目描述

输入一个长度为 n 的整数数列,从小到大输出前 m 小的数。

输入格式

第一行包含整数 n 和 m。

第二行包含 n 个整数,表示整数数列。

输出格式

共一行,包含 m 个整数,表示整数数列中前 m 小的数。

数据范围

\(1≤m≤n≤10^5\)

\(1≤数列中元素≤10^9\)

输入样例:

5 3
4 5 1 3 2

输出样例:

1 2 3

代码:

#include <iostream>
#include <algorithm>
#include <string>
using namespace std;

const int N = 100010;
int h[N];         // 堆数组(1-based)
int ph[N];        // ph[k]:第k个插入的数 → 堆中的下标u
int hp[N];        // hp[u]:堆下标u → 第k个插入的数
int cnt;          // 堆的当前大小
int idx;          // 插入序号(第1、2...个插入)

// 自定义swap:同步维护堆值+ph+hp(核心!必须先swap映射,再swap值)
void heap_swap(int a, int b) 
{
    swap(ph[hp[a]], ph[hp[b]]);  // 交换“插入序号→堆下标”
    swap(hp[a], hp[b]);          // 交换“堆下标→插入序号”
    swap(h[a], h[b]);            // 交换堆值
}

// down操作(仅调用heap_swap)
void down(int u) 
{
    int t = u;
    if (u*2 <= cnt && h[u*2] < h[t]) t = u*2;
    if (u*2+1 <= cnt && h[u*2+1] < h[t]) t = u*2+1;
    if (u != t) 
    {
        heap_swap(u, t);
        down(t);
    }
}

// up操作(仅调用heap_swap)
void up(int u) 
{
    while (u/2 && h[u] < h[u/2]) // u/2>0 等价于 u/2
    {  
        heap_swap(u, u/2);
        u /= 2;
    }
}

// 插入:I x
void heap_insert(int x) 
{
    idx++;                // 插入序号+1
    cnt++;                // 堆大小+1
    ph[idx] = cnt;        // 第idx个插入 → 堆下标cnt
    hp[cnt] = idx;        // 堆下标cnt → 第idx个插入
    h[cnt] = x;           // 堆尾赋值
    up(cnt);              // 上浮
}

// 查询最小值:PM
int heap_get_min() 
{
    return h[1];
}

// 删除最小值:DM(核心修复!必须先swap堆顶和堆尾,再删堆尾)
void heap_delete_min() 
{
    if (cnt == 0) return;
    heap_swap(1, cnt);    // 堆顶和堆尾交换(自动维护映射)
    cnt--;                // 删除堆尾(原堆顶)
    down(1);              // 新堆顶下沉
}

// 删除第k个插入的数:D k
void heap_delete_k(int k) 
{
    if (k < 1 || k > idx || ph[k] == 0) return; // 非法k直接返回
    int u = ph[k];        // 第k个插入 → 堆下标u
    heap_swap(u, cnt);    // u和堆尾交换(维护映射)
    cnt--;                // 删除堆尾(原u位置的数)
    down(u);              // 调整u位置
    up(u);
    ph[k] = 0;            // 清空映射(避免重复访问)
}

// 修改第k个插入的数:C k x
void heap_modify_k(int k, int x) 
{
    if (k < 1 || k > idx || ph[k] == 0) return;
    int u = ph[k];        // 第k个插入 → 堆下标u
    h[u] = x;             // 修改值
    down(u);              // 调整
    up(u);
}

int main() 
{
    ios::sync_with_stdio(false); // 加速cin/cout(避免超时)
    cin.tie(0);
    
    int n;
    cin >> n;
    while (n--) 
    {
        string op;
        cin >> op;
        if (op == "I") 
        {
            int x;
            cin >> x;
            heap_insert(x);
        } 
        else if (op == "PM")  cout << heap_get_min() << '\n';
        else if (op == "DM")  heap_delete_min();
        else if (op == "D") 
        {
            int k;
            cin >> k;
            heap_delete_k(k);
        } 
        else if (op == "C") 
        {
            int k, x;
            cin >> k >> x;
            heap_modify_k(k, x);
        }
    }
    return 0;
}
posted @ 2026-04-06 09:56  CodeMagicianT  阅读(2)  评论(0)    收藏  举报