AcWing 839. 模拟堆--手写堆

AcWing 839. 模拟堆

题目描述

维护一个集合,初始时集合为空,支持如下几种操作:

  1. I x,插入一个数 x;
  2. PM,输出当前集合中的最小值;
  3. DM,删除当前集合中的最小值(数据保证此时的最小值唯一);
  4. D k,删除第 k 个插入的数;
  5. C k x,修改第 k 个插入的数,将其变为 x;

现在要进行 N 次操作,对于所有第 2 个操作,输出当前集合的最小值。

输入格式

第一行包含整数 N。

接下来 N 行,每行包含一个操作指令,操作指令为 I xPMDMD kC k x 中的一种。

输出格式

对于每个输出指令 PM,输出一个结果,表示当前集合中的最小值。

每个结果占一行。

数据范围

1 ≤ N ≤ 1 0 5 , − 1 0 9 ≤ x ≤ 1 0 9 1≤N≤10^5, −10^9≤x≤10^9 1N105,109x109
数据保证合法。

输入样例:
8
I -10
PM
I -10
D 1
C 2 8
I 6
PM
DM
输出样例:
-10
6
#include<bits/stdc++.h>
#include <unordered_map>
using namespace std;
template <typename T> void debug(string s, T x) { cout << s << "=" << x << "\n"; }
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>pll;
typedef pair<int, int>pii;
const ll N = 1e6 + 5;
const ll MOD = 1e9+7;
const ll INF = 0x7fffffff;
//堆是具有以下性质的完全二叉树:
//每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;
//或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆
int heap[N], _size;//从1开始建堆
int ph[N], hp[N];//存储每个节点的映射
int pos;
void heap_swap(int a, int b) {//将两个节点交换
    swap(ph[hp[a]], ph[hp[b]]);//交换他们的映射
    swap(hp[a], hp[b]);
    swap(heap[a], heap[b]);//交换他们的值
}
void down(int u) {
    int minv = u;//t中存储三个点(节点和左右儿子)中的最小值
    int ls = u << 1, rs = u << 1 | 1;
    //判断最小值位置,由于堆的性质先判断左儿子的大小
    if (ls <= _size && heap[ls] < heap[minv])minv = ls;
    if (rs <= _size && heap[rs] < heap[minv])minv = rs;
    if (u != minv) {//如果最小值不是此时的根节点那么要将最小值移动到根节点
        heap_swap(u, minv);
        down(minv);//递归下放换了位置后的节点
    }
}
void up(int u) {
    int root = u >> 1;//取节点的根节点
    while (root != 0 && heap[u] < heap[root]) {//判断节点是否比根小
        heap_swap(u, root);//如果小,则将节点上放至根
        u = root;//更新当前节点
        root = u >> 1;//更新当前根节点
    }
}
void push(int x) {
    _size++;//对的大小++
    pos++;//对应外部的映射++
    ph[pos] = _size;//外部映射指向节点
    hp[_size] = pos;//节点指向外部映射
    heap[_size] = x;//节点的值为x
    up(_size);//插入的位置在最后,所以向上更新

}
int front() {
    return heap[1];//堆顶的位置是1
}
void pop() {
    heap_swap(1, _size);//将最后一个节点和第一个互换
    _size--;//删除最后一个节点
    down(1);//将互换后的堆顶向下更新
}
void del(int k) {
    k = ph[k];//找到第k个插入的数对应的堆的节点
    heap_swap(k, _size);//交换最后一个节点和当前节点
    _size--;//堆大小--
    up(k);//向上或者向下更新结点
    down(k);
}
void modify(int k,int x) {
    k = ph[k];//找到第k个插入的数对应的堆的节点
    heap[k] = x;//将节点修改
    up(k);//向上或者向下更新结点
    down(k);
}
int main() {
    ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);

    int t;
    cin >> t;
    while (t--) {
        string s;
        cin >> s;
        if (s == "I") {
            int x;
            cin >> x;
            push(x);
        }
        else if (s == "PM")cout << front()<<"\n";
        else if (s == "DM")pop();
        else if (s == "D") {
            int k;
            cin >> k;
            del(k);
        }
        else {
            int k, x;
            cin >> k >> x;
            modify(k, x);
        }
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值