单调栈的应用。
思路类似于之前做得一个题,L【i】,R【i】,H【i】分别表示长度为H【i】的长方形的左端点和右端点。显然最大面积等于max{H【i】*(R【i】-L【i】+1)}。
H【i】已知,问题在于L【i】,R【i】怎么求。这里用那个题的思路就不行了。就左端点而言,这里需要求从当前位置i往左第一个长度小于H【i】的。这里可以用一个栈来维护。
如果栈顶长度大于等于H【i】则L【i】即i,否则将栈顶元素岀栈直到栈顶为空或者小于H【i】。栈空说明栈里所有元素都比H【i】大或者相等,则L【i】=1,如果栈顶元素小于H【i】,那么H【i】即栈顶当前元素对应位置。然后将当前位置元素入栈。
为什么这样是正确的呢。因为栈始终是单调非减的。栈顶始终是最大的。但凡在该位置时岀栈的,一定是大于等于当前位置长度的。如果下一个位置的长度比当前位置长度要小,它自然也比之前岀栈这些要小。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <cmath>
#include <stack>
#include <queue>
#include <algorithm>
#define ll long long
#define INF 2139062143
#define inf -2139062144
#define MOD 20071027
#define MAXN 100005
using namespace std;
ll h[MAXN],L[MAXN],R[MAXN];
int main()
{
int n;
while(scanf("%d",&n)&&n)
{
for(int i=1; i<=n; ++i)
scanf("%lld",&h[i]);
L[1]=1;
R[n]=n;
stack<int> left;
left.push(1);
int t;
for(int i=2; i<=n; ++i)
{
while(!left.empty()&&h[left.top()]>=h[i]) left.pop();
if(left.empty()) L[i]=1;
else L[i]=left.top()+1;
left.push(i);
}
stack<int> right;
right.push(n);
for(int i=n-1; i>=1; --i)
{
while(!right.empty()&&h[right.top()]>=h[i]) right.pop();
if(right.empty()) R[i]=n;
else R[i]=right.top()-1;
right.push(i);
}
ll ans=0;
for(int i=1; i<=n; ++i)
ans=max(ans,h[i]*(R[i]-L[i]+1));
printf("%lld\n",ans);
}
return 0;
}