直方图是由在共同基线上排列的矩形序列组成的多边形。矩形具有相等的宽度,但可以具有不同的高度。例如,左边的图显示了由高度为2, 1, 4、5, 1, 3、3的矩形组成的直方图,其中单位为矩形的宽度为1:
通常,直方图用于表示离散分布,例如文本中字符的频率。请注意,矩形的顺序,即它们的高度,是重要的。在直方图中计算最大矩形的面积,该直方图也是在公共基线上对齐的。右边的图形显示了直方图中最大的对齐矩形。
Input
多组测试数据 每组测试数据的第一行为n(1 <= n <= 100000), 表示图形有n个小矩形构成. 接下来一行输入n个整数h1, h2…hn (0 <= hi <= 1000000000, 1 <= i <= n), 表示每个小矩形的高度 n为0时程序结束
Output
仅输出一行表示面积的最大值
Sample Input
7 2 1 4 5 1 3 3
4 1000 1000 1000 1000
0
Sample Output
8
4000
题目没法直接暴力,最开始以为是用尺取法来维护,发现自己总是无法扫描的最后,
看了一下题解发现是使用单调栈。
就是维护一个从小到大的栈。获取两个信息,对于每个节点获取以它为高的最大左边界和最大右边界,然后扫描一遍就可以了。
代码如下:
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstring>
#include<vector>
#include<algorithm>
#include<set>
#include<map>
#include<stack>
#include<cstdio>
using namespace std;
const int MAX = 100010;
typedef long long ll;
#define rep(n) for(int i=1;i<=n;++i)
#define Rrep(n) for(int i=n;i>=1;--i)
ll h[MAX];
int L[MAX], R[MAX];//左右最大边界
int main(void) {
int N;
while (scanf("%d", &N) && N) {
rep(N) {
scanf("%lld", &h[i]);
}
stack<int> st;
rep(N) {
while (!st.empty() && h[st.top()] >= h[i])//如果栈里面比他大.
st.pop();
if (st.empty())
L[i] = 1;//栈为空表示前面的都比他高,所以为最左边界
else
L[i] = st.top() + 1;
st.push(i);
}
while (!st.empty()) st.pop();
//同理获取最大右边界
Rrep(N) {
while (!st.empty() && h[st.top()] >= h[i])
st.pop();
if (st.empty())
R[i] = N;
else
R[i] = st.top() - 1;
st.push(i);
}
ll res = 0;
rep(N) {
res = max(res, h[i] * (R[i] - L[i]+1));
}
printf("%lld\n", res);
}
return 0;
}