单调栈2020-11-24

单调栈

一、分类:
单调递增栈:单调递增栈就是从栈底到栈顶数据是从大到小
单调递减栈:单调递减栈就是从栈底到栈顶数据是从小到大

二、应用:
三、举例:
(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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值