题目地址:
https://www.luogu.com.cn/problem/P3378
题目描述:
给定一个数列,初始为空,请支持下面三种操作:
1.给定一个整数
x
x
x,请将
x
x
x加入到数列中。
2.输出数列中最小的数。
3.删除数列中最小的数(如果有多个数最小,只删除
1
1
1个)。
输入格式:
第一行是一个整数,表示操作的次数
n
n
n。
接下来
n
n
n行,每行表示一次操作。每行首先有一个整数
o
p
op
op表示操作类型。
若
o
p
=
1
op = 1
op=1,则后面有一个整数
x
x
x,表示要将
x
x
x加入数列。
若
o
p
=
2
op = 2
op=2,则表示要求输出数列中的最小数。
若
o
p
=
3
op = 3
op=3,则表示删除数列中的最小数。如果有多个数最小,只删除
1
1
1个。
输出格式:
对于每个操作
2
2
2,输出一行一个整数表示答案。
数据范围:
对于
30
%
30\%
30%的数据,保证
n
≤
15
n \leq 15
n≤15。
对于
70
%
70\%
70%的数据,保证
n
≤
1
0
4
n \leq 10^4
n≤104。
对于
100
%
100\%
100%的数据,保证
1
≤
n
≤
1
0
6
1 \leq n \leq 10^6
1≤n≤106,
1
≤
x
<
2
31
1 \leq x \lt 2^{31}
1≤x<231,
o
p
∈
{
1
,
2
,
3
}
op \in \{1, 2, 3\}
op∈{1,2,3}。
可以用二叉堆实现,代码如下:
#include <iostream>
using namespace std;
const int N = 1e6 + 10;
int n;
int h[N], sz;
void sift_up(int k) {
while (k > 1 && h[k] < h[k / 2]) {
swap(h[k], h[k / 2]);
k /= 2;
}
}
void sift_down(int k) {
while (k * 2 <= sz) {
int t = k;
if (h[k * 2] < h[t]) t = k * 2;
if (k * 2 + 1 <= sz && h[k * 2 + 1] < h[t]) t = k * 2 + 1;
if (t == k) return;
swap(h[k], h[t]);
k = t;
}
}
void push(int x) {
h[++sz] = x;
sift_up(sz);
}
void pop() {
h[1] = h[sz--];
sift_down(1);
}
int main() {
scanf("%d", &n);
while (n--) {
int op, x;
scanf("%d", &op);
if (op == 1) {
scanf("%d", &x);
push(x);
} else if (op == 2) printf("%d\n", h[1]);
else pop();
}
}
每次操作时间复杂度 O ( log n ) O(\log n) O(logn), n n n为数组中有多少个数,空间 O ( n ) O(n) O(n)。