一、内容
问题描述
小明要组织一台晚会,总共准备了 n 个节目。然后晚会的时间有限,他只能最终选择其中的 m 个节目。
这 n 个节目是按照小明设想的顺序给定的,顺序不能改变。
小明发现,观众对于晚上的喜欢程度与前几个节目的好看程度有非常大的关系,他希望选出的第一个节目尽可能好看,在此前提下希望第二个节目尽可能好看,依次类推。
小明给每个节目定义了一个好看值,请你帮助小明选择出 m 个节目,满足他的要求。
输入格式
输入的第一行包含两个整数 n, m ,表示节目的数量和要选择的数量。
第二行包含 n 个整数,依次为每个节目的好看值。
输出格式
输出一行包含 m 个整数,为选出的节目的好看值。
样例输入
5 3
3 1 2 5 4
样例输出
3 5 4
样例说明
选择了第1, 4, 5个节目。
评测用例规模与约定
对于 30% 的评测用例,1 <= n <= 20;
对于 60% 的评测用例,1 <= n <= 100;
对于所有评测用例,1 <= n <= 100000,0 <= 节目的好看值 <= 100000。
二、思路
- 静态查询区间最大值。 首先第一个节目选择的区间为【1, n - m + 1】.查询这个区间的最大值便是第一个节目。得到新的开始位置id。
- 第二个节目的区间为【id+1, n - m】继续查询这个区间的最大值。然后更新id即可。
- 第三个节目[id +1, n - m - 1]… 后面的节目类似。
三、代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100005;
int n, m, p[N];
struct Node {
int maxv, id;
Node(){maxv = id = 0;}
} tr[N << 2];
void pushup(int id, int l, int r) {
if (tr[id << 1].maxv >= tr[id << 1 | 1].maxv) {
tr[id].id = tr[id << 1].id;
tr[id].maxv = tr[id << 1].maxv;
} else {
tr[id].id = tr[id << 1 | 1].id;
tr[id].maxv = tr[id << 1 | 1].maxv;
}
}
void build(int id, int l, int r) {
if (l == r) {
tr[id].id = l; tr[id].maxv = p[l];
return ;
}
int mid = (l + r) >> 1;
build(id << 1, l, mid);
build(id << 1 | 1, mid + 1, r);
pushup(id, l, r);
}
Node query(int id, int l, int r, int x, int y) {
if (x <= l && r <= y) return tr[id];
int mid = (l + r) >> 1;
Node t1, t2;
if (x <= mid) t1 = query(id << 1, l, mid, x, y);
if (y > mid) t2 = query(id << 1 | 1, mid + 1, r, x, y);
if (t1.maxv >= t2.maxv && t1.id != 0) return t1;
else return t2;
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) scanf("%d", &p[i]);
build(1, 1, n);
int t = 0;
while (m--) {
//查询区间[t+1, n - m]
Node q = query(1, 1, n, t + 1, n - m);
if (m != 0) printf("%d ", q.maxv);
else printf("%d", q.maxv);
t = q.id;
}
return 0;
}