1.什么是单调栈
- 具有单调性和栈的性质
- 单调递减栈就是从栈底到栈顶是单调递减的
- 单调递增栈就是从栈底到栈顶是单调递增的
2.单调栈解决的问题
- 以自己为最小值,找到最长的区间;单调递增栈
- 以自己为最大值,找到最长的区间;单调递减栈
- 给定一个区间找到这个区间的最大值或最小值
3.单调递减栈的性质
- 对于第一个出栈的元素,它的右宽一定为0
- 对于第二个出栈的元素,它的右宽为第一个出栈元素的总宽
- 对于第三个出栈的元素,它的右宽为第二个出栈元素的总宽
- 。。。。。。。。
- 直到栈顶元素小于自己,才可以入栈;
- 入栈元素的左宽为上次出栈元素的总宽+1(自身);若无出栈元素,则左宽为1(自身)
- 最后将栈中所有元素出栈,考虑所有情况
(左宽就是左边比自己小的元素个数,右宽就是右边比自己小的元素的个数)
4.以下面数据模拟一下单调递减栈的操作
- 1入栈,无出栈元素,左宽为1;
- 5入栈,无出栈元素,左宽为1;
- 5出栈,第一个出栈右宽为0;
- 4入栈,左宽为上个出栈元素的总宽+1=2;
- 8入栈,无出栈元素,左宽为1;
- 8出栈,第一个出栈,右宽为0;
- 6入栈,左宽为上个出栈的总宽+1;
- 7入栈,无出栈元素,左宽为1;
- 7出栈,第一个出栈,右宽为0;
- 6出栈,第二个出栈,右宽为上个元素的总宽:1;
- 4出栈,第三个出栈,右宽为上个元素的总宽:3;
- 3入栈,左宽为上个出栈的总宽+1:6;
- 3出栈,第一个出栈右宽为0;
- 2入栈,左宽为上一个出栈的总宽+1:7;
- //全部出栈:
- 2出栈,第一个出栈,右宽为0;
- 1出栈,第二个出栈的,右宽为上个出栈的总宽:7;
5. 单调栈的实现
hdu1506(单调递减栈)poj2339,hrbustoj 2326(需long long)
单调递减栈:如果是以各个元素为最大值找到最大区间的话 q[0]=inf, h=inf-1;
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
typedef long long ll;
//int a[maxn];
int q[maxn]={-1};
int w[maxn];//记录左宽,从这个点之前有多少个点的高度大于等于当前点的高度
int main()
{
int n,h;
while(scanf("%d",&n)&&n)
{
int top=0;
ll ans=0;
for(int i=1;i<=n+1;i++)
{
if(i!=n+1)
scanf("%d",&h);
else
h=0;//为了让所有元素出栈
if(h>q[top])
q[++top]=h,w[top]=1;
else
{
ll cnt=0; //第一个出栈的右宽为0;
while(h<=q[top])
{
ans=max(ans,(w[top]+cnt)*q[top]); //(左宽+右宽)*高度;
cnt=cnt+w[top--]; //第(i>1)出栈的右宽为上一个的总宽;
}
//终于找到比自己小的数字了,可以入栈了,入栈会得到左宽,左宽为上一个出栈元素的总宽+1;
q[++top]=h;
w[top]=cnt+1;
}
}
printf("%I64d\n",ans);
}
return 0;
}
//单调栈:从栈顶到栈底单调递减