单调栈模板题 luogu P2659

题目链接:https://www.luogu.org/problem/P2659

实际上就是要我们求出每个数字左右两边第一个小于它的数字位置,然后两个位置所在的开区间长度乘以这个数字,取最大值输出。

因为是求两边第一个小于a[i]的数字,所以我们弄一个递增(其实是不减小就可以了,可以有相同大小的元素)的单调栈,从栈底到栈顶的数字是依次增大的,在求的过程中要始终保持递增的性质。我们每次在数字入栈时求出数字左边第一个小于它的数字位置,在出栈的时候求出右边第一个小于它的数字位置,为什么是这样,看下面,我这里的栈保存的是元素下标,而不是元素值。

L[i]记录左边第一个小于a[i]的元素位置(下标),没有就是0,R[i]记录右边第一个小于a[i]的元素位置,没有就是n+1。

  对于一个a[i],假如a[i]大于栈顶元素(我的栈存的是下标,我们比较是就拿这个下标的值比较),那么如果把a[i]压入栈顶,这个栈还是递增的,这个时候栈顶元素就是第一个小于a[i]的数字,我们直接把L[i]赋值为栈顶元素就行了。

  对于a[i]等于栈顶元素的情况,假如说值都是5好吧,那么其实栈顶的5在它入栈的时候,它的L数组值(它左边第一个小于它的元素位置)我们一定会先得到对吧,那么当前的a[i](也是5),它的L数组值肯定等于栈顶元素的L数组值吧,因为他俩相等,所以直接把a[i]的L数组值赋值为栈顶元素的数组值就可以了,在把a[i]入栈。

  假如a[i]小于栈顶元素,那么如果我们把a[i]压入栈中,那么这个栈里面的元素就不单调递增了,所以说我们需要把栈里面比a[i]大的元素都弹出,假如现在我们要弹出当前栈顶元素,那么其实现在a[i]就是栈顶元素右边的第一个小于栈顶元素的值,所以我们这个时候可以直接把R[s.top()]赋值为i,这样每当我们出栈一个元素,这个元素的左右两边第一个小于它的元素位置就都找到了(左边的在进栈就找到了)。

然后,就没了。

我自己写的板子,应该木有问题,就是慢了点,写的时候那个栈不是s,写成了q,不知道为什么:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<map>
#include<stack>
#include<cmath>
#include<vector>
#include<set>
#include<cstdio>
#include<string>
#include<deque> 
using namespace std;
typedef long long LL;
#define eps 1e-8
#define INF 0x3f3f3f3f
#define maxn 2000005
stack<int>q;
int n,m,k,t;
int a[maxn];
int L[maxn],R[maxn]; 
inline int read(){
    int f=1,x=0;char ch;
    do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
    do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
    return f*x;
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++)
    a[i]=read();
    for(int i=1;i<=n;i++){//线性扫一遍 
        while(!q.empty()&&a[q.top()]>a[i]){//先检查栈顶元素大于a[i]的情况
            int s=q.top();    //保存一下栈顶元素值(下标) 
            R[s]=i;            //得到栈顶元素右边第一个小于它的元素下标 
            q.pop();        //出栈 
        }
        
        if(q.empty())        //假如栈为空 
        L[i]=0;
        else if(a[q.top()]==a[i])    //假如栈顶元素等于a[i],那么L[i]就赋值为栈顶元素的L数组值 
        L[i]=L[q.top()];
        else                        //栈顶元素小于a[i],把a[i]入栈 
        L[i]=q.top();
        
        q.push(i);
    }
    while(!q.empty()){//最后栈顶可能还有元素没有出栈,这个时候他们的R数组值都是n+1,因为右边没有比他们小的值了 
        int s=q.top();
        R[s]=n+1;
        q.pop();
    }
    LL ans=0;
    for(int i=1;i<=n;i++)
    ans=max(ans,(LL)a[i]*(R[i]-L[i]-1)); 
    printf("%lld
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/6262369sss/p/11257259.html