题目描述
维护一个集合,初始时集合为空,支持如下几种操作:
I x
,插入一个数 x;PM
,输出当前集合中的最小值;DM
,删除当前集合中的最小值(数据保证此时的最小值唯一);D k
,删除第 k 个插入的数;C k x
,修改第 k 个插入的数,将其变为 x;
现在要进行 N 次操作,对于所有第 2 个操作,输出当前集合的最小值。
输入格式
第一行包含整数 N。
接下来 N 行,每行包含一个操作指令,操作指令为 I x
,PM
,DM
,D k
或 C k x
中的一种。
输出格式
对于每个输出指令 PM
,输出一个结果,表示当前集合中的最小值。
每个结果占一行。
数据范围
1
≤
N
≤
1
0
5
,
−
1
0
9
≤
x
≤
1
0
9
1≤N≤10^5, −10^9≤x≤10^9
1≤N≤105,−109≤x≤109
数据保证合法。
输入样例:
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;
}