题意:
有n个数,问对于每一个长度为x的连续区间内最小数,最大值为多少?
,输出n个数,分别代表
时的答案。
思路:
考虑每一个数对答案的贡献。
使用单调栈,求出第
个数向左第一个比它小的数的坐标
和向右第一个比它小的数的坐标
,则区间最小值为
的最大区间长度
为:
注意到如果存在长度为 的区间包含 ,则一定存在一个区间长度为 的区间包含 ,故对于答案数组从右到左线性扫描,每一个数与其右边的数取一个最大值即可。
时间复杂度:
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdlib>
using namespace std;
const int A = 1e6 + 10;
int a[A],S[A],L[A],R[A],Ans[A],tot;
int main(){
int n;
scanf("%d",&n);
for(int i=1 ;i<=n ;i++){
scanf("%d",&a[i]);
}
tot = 0;
for(int i=1 ;i<=n ;i++){
while(tot>0 && a[S[tot]]>=a[i]){
tot--;
}
if(!tot) L[i] = 0;
else L[i] = S[tot];
S[++tot] = i;
}
tot = 0;
for(int i=n ;i>=1 ;i--){
while(tot>0 && a[S[tot]]>=a[i]){
tot--;
}
if(!tot) R[i] = n+1;
else R[i] = S[tot];
S[++tot] = i;
}
for(int i=1 ;i<=n ;i++){
int len = R[i] - L[i] - 1;
Ans[len] = max(Ans[len],a[i]);
}
for(int i=n-1 ;i>=1 ;i--){
Ans[i] = max(Ans[i],Ans[i+1]);
}
for(int i=1 ;i<=n ;i++){
printf("%d%c",Ans[i],i==n?'\n':' ');
}
return 0;
}