题意
给出 n 个紧密排列的,宽度为 1 ,高度为 H[i] 的矩形,从这些矩形中画一个最大的矩形,问这个矩形的面积是多少?
思路
假设,最大矩形的高度是 h, 它的左边界是第 l 个矩形,右边界是第 r 个矩形。则有结论,H[l - 1] < l 且 h[r + 1] < h[r],否则,这个矩形就可以向左右扩展得到更大的矩形。由此,我们可以枚举每一个 h,然后求 l 和 r。
其中,求 l 实际上就是求最大的 i 使得 H[i] < h 且 i < h 的序号。这个问题可以用一个栈来解决。栈里保存的是矩形的序号。如果栈顶矩形的高度大于或等于 h,则把它弹出。否则,就找到了高度为 h 的矩形的左边界。之后再把当前矩形压入栈中,再求下一个矩形。同理可以求 r。
在计算 l 或 r 的任意时刻,栈中的元素都是从栈底到栈顶递增的。因此,这种栈成为单调栈。
链接
http://poj.org/problem?id=2559
代码
#include<cstdio>
#include<iostream>
#include<stack>
using namespace std;
const int maxn = 1e5 + 10;
typedef long long LL;
int n;
int H[maxn];
stack<int> st;
int L[maxn], R[maxn];
int main(){
while(scanf("%d", &n) == 1 && n){
for(int i = 0; i < n; ++i){
scanf("%d", H + i);
}
while(!st.empty()) st.pop();
for(int i = 0; i < n; ++i){
while(!st.empty() && H[st.top()] >= H[i]) st.pop();
if(st.empty()) L[i] = 0;
else L[i] = st.top() + 1;
st.push(i);
}
while(!st.empty()) st.pop();
for(int i = n - 1; i >= 0; i--){
while(!st.empty() && H[st.top()] >= H[i]) st.pop();
if(st.empty()) R[i] = n;
else R[i] = st.top();
st.push(i);
}
LL res = 0;
for(int i = 0; i < n; ++i){
res = max(res, (LL) H[i] * (LL)(R[i] - L[i]));
}
cout << res << endl;
}
return 0;
}