小A的柱状图(栈的应用,找左右边界)

链接:https://ac.nowcoder.com/acm/contest/549/H
来源:牛客网

柱状图是有一些宽度相等的矩形下端对齐以后横向排列的图形,但是小A的柱状图却不是一个规范的柱状图,它的每个矩形下端的宽度可以是不相同的一些整数,分别为a[i],每个矩形的高度是h[i],现在小A只想知道,在这个图形里面包含的最大矩形面积是多少。


输入描述:

一行一个整数N,表示长方形的个数
接下来一行N个整数表示每个长方形的宽度
接下来一行N个整数表示每个长方形的高度

输出描述:

一行一个整数,表示最大的矩形面积
示例1

输入

复制
7
1 1 1 1 1 1 1
2 1 4 5 1 3 3

输出

复制
8

说明

样例如图所示,包含的最大矩形面积是8

备注:

1≤n≤1e6,1≤a[i]≤100,1≤h[i]≤1e9;
经典单调栈问题:
可以看看这里的选线法
这个题就是找如果这个i点为最小值,所能到达的最左和最右边界

下面两个思路都是一样的,就是维护一个单调递增的栈(存下标),如果第i个元素比栈顶的小,就一直pop(),然后把这个
进栈,为什么能pop()呢,对后面没有影响吗,答案是没有的因为如果后面来一个大的,他的左边界最多到i这个元素,如果
后面来一个比i更小的,那就已知pop(),没什么影响,可以画图看看。
这是数组模拟
#include<iostream>
#include<algorithm>
#include<cstring>
#include<map>
using namespace std;
typedef long long ll;
const int maxn=2e6+100;
ll a[maxn];
ll b[maxn];
ll l[maxn],r[maxn],sum[maxn];
int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];sum[i] = sum[i - 1] + a[i];
    }
    for(int i=1;i<=n;i++){
        cin>>b[i];
          l[i]=r[i] = i;
    }
    for(int i=1;i<= n;i++)
          while(b[l[i]-1]>=b[i]) l[i]=l[l[i]-1];
    for(int i = n; i >= 1; i--)
          while (b[r[i]+1]>=b[i]) r[i]=r[r[i]+1];
    ll ans=0;
    for (int i = 1; i <= n; i++){
    //    cout<<l[i]<<" "<<r[i]<<endl;
      long long x = b[i] * (sum[r[i]] - sum[l[i] - 1]);
      ans=max(ans,x);
      }
      cout<<ans<<endl;
}

这是单调栈的


#include<bits/stdc++.h>
typedef long long ll;
const int maxn =1e6+5;
using namespace std;
int n,height[maxn],wid[maxn],le[maxn],ri[maxn],b[maxn];//he代表每个矩形的高度,b代表每个矩形的宽度,wid是从1到第i个矩形的总宽度,le ri能到达最左或者最右的第几个矩形 
stack<int>q;
long long ans =0;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>b[i];
        wid[i]=wid[i-1]+b[i];
    }
    for(int i=1;i<=n;i++)
    {
        cin>>height[i];
    }
    for(int i=1;i<=n;i++)//找每个矩形能到达最左 
    {
        while(!q.empty()&&height[q.top()]>=height[i]) q.pop();
        if(q.empty()) le[i]=1;
        else le[i]=q.top()+1;
        q.push(i);
    }
    while(!q.empty()) q.pop();//一定要清栈剩余元素 
    for(int i=n;i>=1;i--) //找每个矩形能到达最右 
    {
        while(!q.empty()&&height[q.top()]>=height[i]) q.pop();
        if(q.empty()) ri[i]=n;
        else ri[i]=q.top()-1;
        q.push(i);
    }
    for(int i=1;i<=n;i++) //找最大值 
    {
        ans =max (ans,(1LL)*(wid[ri[i]]-wid[le[i]-1])*height[i]);
    }
    cout<<ans<<endl;
    return 0;
}

 

 
来一个更小的那没有什么
posted @ 2021-01-25 21:39  lipu123  阅读(84)  评论(0编辑  收藏  举报