小A的柱状图(栈的应用,找左右边界)
链接:https://ac.nowcoder.com/acm/contest/549/H
来源:牛客网
柱状图是有一些宽度相等的矩形下端对齐以后横向排列的图形,但是小A的柱状图却不是一个规范的柱状图,它的每个矩形下端的宽度可以是不相同的一些整数,分别为a[i],每个矩形的高度是h[i],现在小A只想知道,在这个图形里面包含的最大矩形面积是多少。
输入描述:
一行一个整数N,表示长方形的个数
接下来一行N个整数表示每个长方形的宽度
接下来一行N个整数表示每个长方形的高度
输出描述:
一行一个整数,表示最大的矩形面积
备注:
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; }
来一个更小的那没有什么