单调栈

通过一个例子,简要证明一下单调栈  。   poj2796

单调栈 就是维护一个栈使这个栈里面的元素是单调递增还是单调递减的!!!
那么用一个题目来理解一下他的原理。
  
这个题的意思就是说在一个[L,R]区间内,存在一个最小的数,其余的数都比它大。然后求max(这个区间的和*最小的数)。

首先维护一个单调递增的栈。设处在当前栈顶的元素为x,扫面到的当前元素为i,那么首先可以判断的是既然x处于栈顶,那么肯定a[x+1]>=a[x],然后因为i此时要入栈,那么a[i]>a[x],那么此时既然a[x+1]不在栈顶,那么肯定a[x+1]>a[i],说明最左边的大于a[i]的数应该是x+1。这是入栈的情况。。。


那么出栈呢??因为此时这个元素要出栈了,如果它的右边界再不更新,就再也没机会了,所以要更新右边界。。因为a[i]<a[x],所以a[i-1]肯定会大于a[x]即a[i-1]>a[x],即a[i-1]>a[x]>a[i],故右边界为i-1.


那么左右边界都出来了  如果一个元素始终没有出栈  说明说明????


即右边界为n。。

代码


#include<cstdio>
#include<iostream>
#include<algorithm>
#include<stack>
#include<cstring>
typedef long long LL;


using namespace std;


const int maxn=100000+10;


LL pre[maxn];


int le[maxn],ri[maxn],a[maxn];


struct Node
{
    int pos,integer;
};


stack<Node>s;


void solve(Node tmp)
{
    int i=tmp.pos;
    int value=tmp.integer;
    le[i]=i,ri[i]=-1;
    Node ff;
    if(!s.empty())  ff=s.top();
    if(ff.integer==value)
    {
        le[i]=ff.pos;
        s.push(tmp);
        return;
    }
    else
    {
        while(!s.empty()&&ff.integer>value)
        {
            int pos=ff.pos;
            ri[pos]=i-1;
            s.pop();
            if(!s.empty())  ff=s.top();
            else break;
        }
    }
    if(!s.empty())
    {
        le[i]=ff.pos+1;
        s.push(tmp);
    }
    else
    {
        le[i]=1;
        s.push(tmp);
    }
}


int main()
{
   int n,ans_l,ans_r;
   LL ans;
   while(~scanf("%d",&n))
   {
        Node tmp;
        memset(pre,0,sizeof(pre));
        while(!s.empty())  s.pop();
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&tmp.integer);
            a[i]=tmp.integer;
            if(i==1)  pre[i]=tmp.integer;
            else pre[i]=pre[i-1]+tmp.integer;
            tmp.pos=i;
            solve(tmp);
        }
        ans=-1;
        for(int i=1;i<=n;i++)
        {
            if(ri[i]==-1)  ri[i]=n;
          //  printf("%d %d %d\n",i,le[i],ri[i]);
            if(ans<a[i]*(pre[ri[i]]-pre[le[i]-1]))
            {
                ans=a[i]*(pre[ri[i]]-pre[le[i]-1]);
                ans_l=le[i];
                ans_r=ri[i];
            }
        }
        printf("%I64d\n",ans);
        printf("%d %d\n",ans_l,ans_r);
   }
   return 0;
}








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值