通过一个例子,简要证明一下单调栈 。 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;
}