b_lq_晚会界面单(线段树维护区间最大值表+预留m个位置)

从n个节目中选m个,且所选节目是按照小明设想的顺序给定的,顺序不能改变。
小明发现,观众对于晚会的喜欢程度与前几个节目的好看程度有非常大的关系,
他希望选出的第一个节目尽可能好看,在此前提下希望第二个节目尽可能好看,依次类推。
1 <= n <= 100000,0 <= 节目的好看值 <= 100000

输入
5 3
3 1 2 5 4
输出:3 5 4

先从[1,n-m+1](p1指向区间起点,p2指向区间末尾)中选一个最大值,且记录下标为p,因为p已经是最好看的了,又因为顺序不能改,下一个界面只能从 [p,p2+1] 中选,看看我构造的这组数据就明白了

输入
5 3
3 4 5 1 2
输出
5 1 2
//虽然第1和第2个界面都比第4、5个界面好看,但因为顺序不难改,所以只能选第4、5个了
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int a[N], mx[N<<1];
void pushUp(int k) {
    int l=mx[k<<1], r=mx[k<<1|1];
    mx[k]=a[l]>=a[r] ? l : r;
}
void build(int l, int r, int k) {
    if (l==r) {
        mx[k]=l;
        return;
    }
    int m=l+r>>1;
    build(l,m,k<<1);
    build(m+1,r,k<<1|1);
    pushUp(k);
}
//在[ql,qr]中找最大值下表
int query(int ql, int qr, int l, int r, int k) {
    if (ql<=l && r<=qr) {
        return mx[k];
    }
    int m=l+r>>1, pos=-1;
    if (m>=ql) pos=query(ql,qr,l,m,k<<1);
    if (m<qr) {
        if (pos==-1) pos=query(ql,qr,m+1,r,k<<1|1);
        else {
            int t=query(ql,qr,m+1,r,k<<1|1);
            if (a[t]>a[pos]) pos=t;
        }
    }
    return pos;
}
int main() {
    std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    int n,m; cin>>n>>m;
    for (int i=1; i<=n; i++) cin>>a[i];
    build(1,n,1);
    int p1=1, p2=n-m+1; //预留出m个界面
    while (p1<p2 && p2<=n) {
        int p=query(p1,p2,1,n,1);
        printf("%d ", a[p]);
        p1=p+1, p2++;
    }
    //如果p1和p2重合或者p1>p2的话,则证明前面没选够m个
    while (p2<=n) printf("%d ", a[p2++]);
    return 0;
}
posted @ 2020-10-12 20:26  童年の波鞋  阅读(76)  评论(0编辑  收藏  举报