单调栈

关于单调栈的简单介绍请看这篇博客:https://blog.csdn.net/liujian20150808/article/details/50752861

总结:
一个元素向左遍历的第一个比它小的数的位置就是将它插入单调栈时栈顶元素的值,若栈为空,则说明不存在这么一个数。然后将此元素的下标存入栈,就能类似迭代般地求解后面的元素

模板:

stack<int >S;
    for(int i=1;i<=n;i++){
        while(S.size()&&a[S.top()]>=a[i]) S.pop();
        
        if(S.empty()) L[i]=0;
        else L[i]=S.top();
        
        S.push(i);
    }

例题:HDU1506

Largest Rectangle in a Histogram

http://acm.hdu.edu.cn/showproblem.php?pid=1506
首先考虑最大面积的矩形X的左右边界的性质:

设其左边界为L,右边界为R,则其高H = min{h[i] | L <= i <= R}

此时最大面积为 (R - L + 1) * H

若此时左边界的左边那个矩形的高度 h[L-1] >= H
则左边界可以向左拓展,则新的面积为:

(R - (L-1) + 1) * H > 原面积

则与原假设条件冲突

故左边界左边的那个矩形的高度 :h[L-1] < H
同理右边界右边的那个矩形的高度: h[R+1] < H

设H = h[i]

所以左边界L是满足h[j-1] < h[i]的最大的j,即从i点向左遍历的第一个高度比i小的点的右边一个点
而右边界R是满足 h[j+1] < h[i]的最小的j,即从i点向右遍历第一个高度比i小的点的左边一个点
所以我们可以利用单调栈的性质得到每个确定点,即确定高度的最大面积矩形的左右边界,然后枚举取最大即可。

#include <bits/stdc++.h>
using namespace std;
const int N=100000+100;
typedef long long ll;

stack<int>S;
ll h[N];
int R[N],L[N];

int main(){
    int n;
    while(~scanf("%d",&n)&&n){
        for(int i=0;i<n;i++) scanf("%lld",&h[i]);

        while(S.size()) S.pop();

    for(int i=0;i<n;i++){
        while(S.size()&&h[S.top()]>=h[i]) S.pop();

        if(S.empty()) L[i]=0;
        else L[i]=S.top()+1;

        S.push(i);
        }

        while(S.size()) S.pop();

        for(int i=n-1;i>=0;i--){
            while(S.size()&&h[S.top()]>=h[i]) S.pop();

            if(S.empty()) R[i]=n;
            else  R[i]=S.top();

        S.push(i);
        }

        ll ans=0;
        for(int i=0;i<n;i++){
            ans=max(ans,h[i]*(R[i]-L[i]));
        }
        printf("%lld\n",ans);
    }
    return 0;
}

例题:http://poj.org/problem?id=3250

Bad Hair Day

很裸的单调栈,而且只需要跑一个方向。

#include <iostream>
#include <algorithm>
#include <stack>
#include <stdio.h>
using namespace std;
const int N=100000+100;
typedef long long ll;

stack<int>S;
ll h[N];
int R[N],L[N];

int main(){
   int n;
   cin>>n;
   for(int i=0;i<n;i++){
    scanf("%lld",&h[i]);
   }

    h[n]=0x3f3f3f3f;
   for(int i=n;i>=0;i--){
    while(S.size()&&h[S.top()]<h[i]) S.pop();

    if(S.empty()) R[i]=0;
    else R[i]=S.top()-i-1;
    S.push(i);
   }
   ll num=0;
   for(int i=0;i<n;i++){
       // cout<<R[i]<<" ";
    if(R[i]!=0) num+=R[i];
   }
   cout<<num<<endl;
}

例题:http://poj.org/problem?id=2796

Feel Good

经典单调栈

#include <iostream>
#include <algorithm>
#include <stack>
#include <stdio.h>
#include <cstring>
using namespace std;
const int N=100000+100;
typedef long long ll;

stack<int>S;
ll h[N];
ll R[N],L[N],Sum[N];

int main(){
   int n,t=0;
   scanf("%d",&n);
   	Sum[0]=0;
   for(int i=1;i<=n;i++){
    scanf("%lld",&h[i]);
    Sum[i]=Sum[i-1]+h[i];
   }
   while(S.size()) S.pop();

    for(int i=1;i<=n;i++){
        while(S.size()&&h[S.top()]>=h[i]) S.pop();

        if(S.empty()) L[i]=0;
        else L[i]=S.top();

        S.push(i);
        }

        while(S.size()) S.pop();

        for(int i=n;i>=1;i--){
            while(S.size()&&h[S.top()]>=h[i]) S.pop();

            if(S.empty()) R[i]=n;
            else  R[i]=S.top()-1;

        S.push(i);
        }

    //for(int i=0;i<n;i++) printf("%d ",L[i]);
    //printf("\n");
   // for(int i=0;i<n;i++) printf("%d ",R[i]);
    //printf("\n");
   ll maxs=-1,rr,ll,r,l;
   for(int i=1;i<=n;i++){
    if(maxs<h[i]*(Sum[R[i]]-Sum[L[i]])){
           rr=R[i];
           ll=L[i]+1;
           maxs=h[i]*(Sum[R[i]]-Sum[L[i]]);

       }
   }
    printf("%lld\n%lld %lld\n",maxs,ll,rr);
   return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值