51Nod 1437 单调栈

题目链接


题意:
有n个数,问对于每一个长度为x的连续区间内最小数,最大值为多少?
x [ 1 , n ] ,输出n个数,分别代表 x = i 时的答案。


思路:
考虑每一个数对答案的贡献。

使用单调栈,求出第 i 个数向左第一个比它小的数的坐标 L [ i ] 和向右第一个比它小的数的坐标 R [ i ] ,则区间最小值为 a [ i ] 的最大区间长度 l e n 为:

l e n = R [ i ] L [ i ] 1

注意到如果存在长度为 l e n 的区间包含 a [ i ] ,则一定存在一个区间长度为 l e n 1 的区间包含 a [ i ] ,故对于答案数组从右到左线性扫描,每一个数与其右边的数取一个最大值即可。

时间复杂度: O ( 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;
}

猜你喜欢

转载自blog.csdn.net/wubaizhe/article/details/79958489