AcWing131. 直方图中最大的矩形


直方图的最大面积

题意

直方图是由在公共基线处对齐的一系列矩形组成的多边形。

矩形具有相同的宽度,但可以有不同的高度。

例如,下图显示了高度为 \(2, 1, 4, 5, 1, 3, 3\) 的矩形组成的直方图。

请问直方图上最大的对齐矩阵面积为多少?

分析

首先可以发现最大的对齐矩阵的高度,一定是某个矩形的高度。

暴力分析,对每一个矩阵 \(i\),我们假设它的高度 \(h(i)\) 为最大面积的高度,求出从这个矩形开始向左右最多扩展多少,假设最多扩展到 \([l, r]\) 那么其面积为 \((r - l + 1) \times h(i)\) 。只要求出所有这样的矩形最大值即可。

考虑优化,对于矩形 \(i\) ,假设 \(j \lt k \lt i\) ,且 \(h(j) > h(k)\) ,那么我们不需要考虑 \(h(j)\) 。因为如果 \(h(k) >= h(i)\) 那么一定有 \(h(j) >= h(i)\) ,所以可以用单调栈优化。

从前往后找出每个矩形最多扩展的左端点,右端点同理。

Code

#include 
using namespace std;

const int N = 100010;

// 单调栈优化暴力,l[i] 存储i号矩形向左的界限
int stk[N], top, l[N], r[N];
int n, a[N];

int main ()
{
    while( cin >> n, n )
    {
        top = 0;
        for (int i = 1; i <= n; i ++ ) cin >> a[i];
        // 找出每个矩形左界限
        for (int i = 1; i <= n; i ++ )
        {
            while(top && a[stk[top]] >= a[i]) -- top;
            if (!top) l[i] = 1; else l[i] = stk[top] + 1;
            stk[++ top] = i;
        }
        top = 0;
        // 找出每个矩形的右界限
        for (int i = n; i >= 1; i -- )
        {
            while(top && a[stk[top]] >= a[i]) -- top;
            if (!top) r[i] = n; else r[i] = stk[top] - 1;
            stk[++ top] = i;
        }
        long long mx = -1;
        for (int i = 1; i <= n; i ++ )
        {
            int le = l[i], ri = r[i];
            long long cur = 1ll * (ri - le + 1) * a[i];
            mx = max(mx, cur);
        }
        cout << mx << endl;
    }
    return 0;