利用线段树查询一段区间内的最大值(值,下标)

题目举例:

小明要组织一台晚会,总共准备了 n 个节目。然后晚会的时间有限,他只能最终选择其中的 m 个节目。
这 n 个节目是按照小明设想的顺序给定的,顺序不能改变。
小明发现,观众对于晚会的喜欢程度与前几个节目的好看程度有非常大的关系,他希望选出的第一个节目尽可能好看,在此前提下希望第二个节目尽可能好看,依次类推。
小明给每个节目定义了一个好看值,请你帮助小明选择出 m 个节目,满足他的要求。

简单的暴力思路,利用尺取法。
第一次区间为[0,n-m]
第二次区间为[lastmax_index,n-m+1]个这样的区间

可以优化的地方就是怎么查询在这个区间中的最大值的下标—线段树

#include 
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;
}	

你可能感兴趣的:(树,线段树)