ACM题集:https://blog.csdn.net/weixin_39778570/article/details/83187443
题目:http://poj.org/problem?id=2559
题意:求最大子矩形的面积.
解法:
把高度看成一个序列,当高度递增的时候,答案在这个递增序列往回寻找。例如,
1,2,3,4,5,6;更新答案的时候有这么几个选择(6x1),(5x2),(4x3),(3x4),(2x5),(1x6).(高x宽)
当高度出现下降的时候,这时左端比它高的矩形有一部分是无用的。
例如,1,2,3,4,5,6,4;可以看出1,2,3,4,4,4;因为我们采取往左更新的方式,5,6这两个大于4的部分是无法被使用上的(往右更新也一样)。所以我们可以把5,6,4这三个矩形合并成一个高度为4,宽度为3的矩形,使得整个序列单调递增.
以下是单调栈算法
/*单调栈*/
#include<cstdio>
#include<algorithm>
#define ll long long
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std;
int n;
ll h[100005],w[100005],s[100005]; // 单调递增栈
void solve(){
ll ans = 0;
h[n+1] = 0; // 最右端设置为0,以便清空栈,遍历完整个栈
int pos = 0;
fo(i,1,n+1){
if(s[pos]<=h[i]){ // 单调不下降,入栈
s[++pos]=h[i];
w[pos]=1;
}else{
int width = 0;
while(s[pos]>h[i]){ // 往回走,每往回走一步都是一个矩形
width += w[pos];
ans = max(ans, s[pos]*width); // 取栈顶,往回更新
pos--; // 删除栈顶元素
}
s[++pos] = h[i]; // 合并成新的矩形入栈
w[pos] = width+1;
}
}
printf("%lld\n",ans);
}
int main(){
while(scanf("%d",&n)&&n){
fo(i,1,n)scanf("%lld",&h[i]);
solve();
}
return 0;
}