NCSTOJ:[算法竞赛进阶指南]直方图中最大的矩形

B : [算法竞赛进阶指南]直方图中最大的矩形
Time Limit:2 Sec Memory Limit:128 MiB
Back Submit Edit

Description
【poj 2559】

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

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

例如,图例左侧显示了由高度为2,1,4,5,1,3,3的矩形组成的直方图,矩形的宽度都为1:

通常,直方图用于表示离散分布,例如,文本中字符的频率。
现在,请你计算在公共基线处对齐的直方图中最大矩形的面积。

图例右图显示了所描绘直方图的最大对齐矩形。

Input
输入包含几个测试用例。

每个测试用例占据一行,用以描述一个直方图,并以整数n开始,表示组成直方图的矩形数目。

然后跟随n个整数h1,…,hn。这些数字以从左到右的顺序表示直方图的各个矩形的高度。

每个矩形的宽度为1。同行数字用空格隔开。

当输入用例为n=0时,结束输入,且该用例不用考虑。

数据范围:

1 ≤ n ≤ 100000,

0 ≤ hi ≤ 1000000000

Output
对于每一个测试用例,输出一个整数,代表指定直方图中最大矩形的区域面积。

每个数据占一行。请注意,此矩形必须在公共基线处对齐。

Sample Input
7 2 1 4 5 1 3 3
4 1000 1000 1000 1000
0
Sample Output
8
4000

#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=100010;
long long int f[maxn],w[maxn],s[maxn];//f记录原数组,w【p】表示的是从p位置往前包括它自己且是连续的有多少个大于等于它的长方体
long long  p,ans;//p代表的是栈顶指针ans表示的是最终结果的记录
int main() {
    int n;
    while(cin>>n&&n) {
        p=0;//栈顶指针指向0位置
        ans=0;//结果清零
        for(int i=1; i<=n; i++)
            scanf("%d",&f[i]);
        f[n+1]=0;
        for(int i=1; i<=n+1; i++) {
            if(f[i]>s[p])s[++p]=f[i],w[p]=1;//当入栈数据大于栈顶数据时可以入栈并且记录其入栈的初始宽度为1
            else {
                int width=0;
                while(s[p]>f[i]) { //当入栈元素小于栈顶元素时为了维护栈的单调性需要进行出栈操作
                    //而在一个数出栈前应该计算一下它能形成的最大长方形的面积
                    //这是因为栈顶元素往后是不可能形成最大长方形了因为要入栈元素比它大
                    //而要计算它之前有多少个与他连续且比他大的
                    width+=w[p];//因为w[p]是记录栈顶元素之前有多少个比他大且连续的个数即宽度
                    //而这是可以由新加入的小元素继承的
                    //且表示的是由原来栈顶元素往前连续推的比他大的个数
                    ans=max(ans,(long long int)width*s[p]);
                    //结果更新是这样理解的栈顶元素乘以往后的连续的个数(有因为是单调栈)width起到记录由高到低的个数
                    p--;//出栈
                }
                s[++p]=f[i];
                w[p]=width+1;//初始计算宽度的时候是没有把它自身的宽度计算上去的

            }


        }


cout<<ans<<endl;





    }

return 0;


}

你可能感兴趣的:(单调栈)