单调栈
一、分类:
单调递增栈:单调递增栈就是从栈底到栈顶数据是从大到小
单调递减栈:单调递减栈就是从栈底到栈顶数据是从小到大
二、应用:
三、举例:
(1)http://acm.hdu.edu.cn/showproblem.php?pid=1506
题目大意:给你一个直方图,告诉你各个条形矩形的高度,求基线对齐构成的矩形中最大的矩形的面积。
解析:枚举对于每一个矩形,面积 = a[i]*(r-l-1),其中了,l,r是左右边界,找到左右边界是关键。
#include <bits/stdc++.h>
using namespace std;
#define rep(i,x,y) for(int i=(x);i<=(y);i++)
const int M=1e5+2;
int a[M],l[M],r[M],st[M];//a[]存各矩形的高,l[i]存从第i个矩形左边数第一个比a[i]小的数,r[i]存从第i个矩形右边数第一个比a[i]小的数
int read()
{
char c=getchar();
int w=1,s=0;
while(c<'0'||c>'9')
{
if(c=='-')w=-1;
c=getchar();
}
while(c>='0'&&c<='9')
{
s=(s<<1)+(s<<3)+(c^48);
c=getchar();
}
return w*s;
}
int main()
{
int n;
while(scanf("%d",&n),n)
{
if(n==0)break;
rep(i,1,n)a[i]=read();
int top=0;st[0]=0;
rep(i,1,n)
{
while(top&&a[st[top]]>=a[i])top--;//单调递减栈
l[i]=st[top];
st[++top]=i;
}
top=0;st[0]=n+1;
for(int i=n;i>0;i--)
{
while(top&&a[st[top]]>=a[i])top--;//单调递减栈
r[i]=st[top];
st[++top]=i;
}
long long ans=0;
rep(i,1,n)
{
ans=max(ans,(1ll)*(r[i]-l[i]-1)*a[i])//r-l-1为以第i个矩形
}
printf("%lld\n",ans);
}
return 0;
}
(2)http://acm.hdu.edu.cn/showproblem.php?pid=3410
题目大意:分别找出每个数据(从此数据开始数)左边比此值小的数据中的最大值的位置和右边比此值小的数据中的最大值的位置,如没有则输出0。
#include <bits/stdc++.h>
using namespace std;
#define rep(i,x,y) for(int i=(x);i<=(y);i++)
const int M=1e5+2;
int a[M],l[M],r[M],st[M];
int read()
{
char c=getchar();
int w=1,s=0;
while(c<'0'||c>'9')
{
if(c=='-')w=-1;
c=getchar();
}
while(c>='0'&&c<='9')
{
s=(s<<1)+(s<<3)+(c^48);
c=getchar();
}
return w*s;
}
int main()
{
int t,cnt=1;
t=read();
while(t--)
{
int n;
n=read();
for(int i=1;i<=n;i++)a[i]=read();
int top=0;st[0]=0;
rep(i,1,n)
{
int maxx=-1,k=0;
while(top&&a[st[top]]<=a[i])
{
if(maxx<a[st[top]])k=st[top],maxx=a[st[top]];//使跳出循环后k为从i开始数的左边比此值小的数据中的最大值
top--;
}
l[i]=k;
st[++top]=i;
}
top=0,st[0]=n+1;
for(int i=n;i>0;i--)
{
int maxx=-1,k=0;
while(top&&a[st[top]]<=a[i])
{
if(maxx<a[st[top]])k=st[top],maxx=a[st[top]];//使跳出循环后k为从i开始数的右边比此值小的数据中的最大值
top--;
}
r[i]=k;
st[++top]=i;
}
printf("Case %d:\n",cnt++);
rep(i,1,n)
{
printf("%d %d\n",l[i],r[i]);
}
}
return 0;
}