蓝桥杯模拟赛——晚会节目单(线段树)

题目
【问题描述】
小明要组织一台晚会,总共准备了 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。

 坑点:最重要的是红色字体部分,意思就是求出n个树中选m个,相对顺序不变,求字典序最大的;由此第一个数肯定要在区间[1,n-m+1]中选择最大的那个数,因为要保证后面还剩下至少m-1个数才可,以此类推,选第二个数也要遵循这样的原则。这样就要求不定区间的最大值,线段树。

 

#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
struct node{
	int l,r,maxn;//maxn 表示区间[l,r]最大值的下标
}a[400010];
int ans[100010];
int data_s[100010];
void update(int k){
	if(data_s[a[k<<1].maxn]>=data_s[a[k<<1|1].maxn]){//注意比较的对象
		a[k].maxn=a[k<<1].maxn;
	} 
	else a[k].maxn=a[k<<1|1].maxn;
}
void build(int k,int l,int r){
	a[k].l=l;
	a[k].r=r;
	if(l==r){
		a[k].maxn=l;
		return ;
	}
	int mid=(l+r)>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
	update(k);
}
int query(int k,int l,int r){
	if(a[k].l>=l&&a[k].r<=r){
		return a[k].maxn;
	}
	int maxn=0;
	int mid=(a[k].l+a[k].r)>>1;
    //最好使用三段式//判断mid 和区间的三个关系
	if(mid>=l&&mid=data_s[right])maxn=left;
        else maxn=right;
        return maxn;
	}
	if(mid=r)return query(k<<1,l,r);// 3
}
int main(){
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>data_s[i];
	}
	build(1,1,n);
    ans[0]=0;
	for(int k=1;k<=m;k++){
		ans[k]=query(1,ans[k-1]+1,n-(m-k));//每次能访问的区间是[ans[k-1]+1,n-(m-k)];
	}
	for(int i=1;i<=m;i++){
		if(i==m)cout<_/___.'  >'"".
//              | | :  `- \`.;`\ _ /`;.`/ - ` : | |
//              \  \ `-.   \_ __\ /__ _/   .-` /  /
//         ======`-.____`-.___\_____/___.-`____.-'======
//                            `=---='
//        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//

 

你可能感兴趣的:(线段树和树状数组)