题目举例:
小明要组织一台晚会,总共准备了 n 个节目。然后晚会的时间有限,他只能最终选择其中的 m 个节目。
这 n 个节目是按照小明设想的顺序给定的,顺序不能改变。
小明发现,观众对于晚会的喜欢程度与前几个节目的好看程度有非常大的关系,他希望选出的第一个节目尽可能好看,在此前提下希望第二个节目尽可能好看,依次类推。
小明给每个节目定义了一个好看值,请你帮助小明选择出 m 个节目,满足他的要求。
简单的暴力思路,利用尺取法。
第一次区间为[0,n-m]
第二次区间为[lastmax_index,n-m+1]个这样的区间
可以优化的地方就是怎么查询在这个区间中的最大值的下标—线段树
#include <bits/stdc++.h>
using namespace std;
int N, M;
vector<int> data;
const int MAX_N = 100000 * 4;
int tree[MAX_N];
void buildSegTree(int rt, int l, int r) {//tree存放的是最大值的下标
if (l == r) {
tree[rt] = l;
return;
}
int mid = l + ((r - l) >> 1);
buildSegTree(rt<<1, l, mid);
buildSegTree(rt<<1|1, mid + 1, r);
int index1 = tree[rt<<1];
int index2 = tree[rt<<1|1];
tree[rt] = data[index1] > data[index2] ? index1 : index2;
}
int query(int l, int r, int ql, int qr, int rt) {
if (ql <= l && qr >= r) return tree[rt];
int mid = l + ((r - l) >> 1);
int ans = -1;
if (ql <= mid)
ans = query(l, mid, ql, qr, rt << 1);
if (qr > mid){
if(ans==-1)
ans = query(mid + 1, r, ql, qr, rt << 1 | 1);
else{
int _index = query(mid + 1, r, ql, qr, rt << 1 | 1);
if (data[_index]>data[ans])
ans = _index;
}
}
return ans;
}
void work() {
cin >> N >> M;
data = vector<int>(N);
for (int i = 0; i < N; i++)
cin >> data[i];
buildSegTree(1, 0, N - 1);
int pos_max = 0, pos_1 = 0, pos_2 = N - M;
while (pos_1 < pos_2 && pos_2 < N) {
pos_max = query(0, N - 1, pos_1, pos_2, 1);
cout << data[pos_max] << " ";
pos_1 = pos_max + 1;
pos_2++;
}
while (pos_2 != N)
cout << data[pos_2++] << " ";
cout << endl;
}
int main() {
work();
return 0;
}