题目
【问题描述】
小明要组织一台晚会,总共准备了 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。
思路:线段树维护区域最大值所在处的下标。
#include<iostream>
#include<cstring>
#include<stack>
#include<ctime>
#define ll long long
using namespace std;
const int N = 100000 + 10;
int lg[N]={-1};
int tree[N*4];
int data[N];
int _pow(int a)
{
return 1<<a;
}
void build_tree(int node, int l, int r)
{
if(l == r)
{
tree[node] = l;
return;
}
int mid = (l + r) / 2;
int left = node * 2;
int right = left + 1;
build_tree(left, l, mid);
build_tree(right, mid + 1, r);
int a = tree[left];
int b = tree[right];
tree[node] = data[a] > data[b] ? a : b;
}
int query(int l, int r, int ql, int qr, int node)
{
if(ql <= l && qr >= r) return tree[node];
int mid = (l + r) / 2;
int ans = -1;
if(ql <= mid) ans = query(l, mid, ql, qr, node * 2);
if(qr > mid)
{
if(ans == -1) ans = query(mid+1, r, ql, qr, node * 2 + 1);
else
{
int k = query(mid+1, r, ql, qr, node * 2 + 1);
ans = data[ans] > data[k] ? ans : k;
}
}
return ans;
}
int main()
{
int n,m;
cin>>n>>m;
for(int i=1; i<=n; i++)
{
scanf("%d",&data[i]);
lg[i] = lg[i/2] + 1;
}
build_tree(1,1,n);
int pos1 = 1, pos2 = n-m+1, pos_max = 1;
while(pos1 < pos2 && pos2 <= n)
{
pos_max = query(1,n,pos1,pos2,1);
printf("%d ",data[pos_max]);
pos1 = pos_max + 1;
pos2++;
}
while(pos2 != n+1)
{
printf("%d ",data[pos2++]);
}
return 0;
}