HDU - 1506(单调队列) - Largest Rectangle in a Histogram

Largest Rectangle in a Histogram

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 18907    Accepted Submission(s): 5667


Problem Description
A histogram is a polygon composed of a sequence of rectangles aligned at a common base line. The rectangles have equal widths but may have different heights. For example, the figure on the left shows the histogram that consists of rectangles with the heights 2, 1, 4, 5, 1, 3, 3, measured in units where 1 is the width of the rectangles:

Usually, histograms are used to represent discrete distributions, e.g., the frequencies of characters in texts. Note that the order of the rectangles, i.e., their heights, is important. Calculate the area of the largest rectangle in a histogram that is aligned at the common base line, too. The figure on the right shows the largest aligned rectangle for the depicted histogram.
 

Input
The input contains several test cases. Each test case describes a histogram and starts with an integer n, denoting the number of rectangles it is composed of. You may assume that 1 <= n <= 100000. Then follow n integers h1, ..., hn, where 0 <= hi <= 1000000000. These numbers denote the heights of the rectangles of the histogram in left-to-right order. The width of each rectangle is 1. A zero follows the input for the last test case.
 

Output
For each test case output on a single line the area of the largest rectangle in the specified histogram. Remember that this rectangle must be aligned at the common base line.
 

Sample Input
 
   
7 2 1 4 5 1 3 3 4 1000 1000 1000 1000 0
 

Sample Output
 
   
8 4000
 

单调队列呢,是一种队列中元素呈单调性的队列(感觉就是个数组模拟了一波)。单调队列只能在尾部插入元素,却可以从两端取数值,且保证是这个队列的最小值和最大值。

插入一个数时,将队列中所有大于等于这个数值的数弹出。因为每个数只会被放入队列一次,弹出队列一次,所以平摊下来整体的复杂度是O(n)的。

初始化问题也很值得注意,他决定了当队列中不存在数时候的边界值。

在此感谢卿爷的耐心教导,尽管我早已经是个退役菜鸡orzzzzzz

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define INF 0x3f3f3f3f3f3f3f
using namespace std;
const int MAXN = 1e5 + 10;

int a[MAXN];
int le[MAXN], ri[MAXN];
int q[MAXN];

int main()
{

    int n;
    while (scanf("%d", &n) && n) {
        for (int i = 1; i <= n; ++i) {
            scanf("%d", &a[i]);
        }
        int top = 0;
        q[0] = 0;   //=0是因为,当队列中没有数时,所有数的左边界都是0+1=1
        for (int i = 1; i <= n; ++i) {
            //将所有>=的数都弹出,那样就可以直接取到最左边的边界
            //如 1 5 5 5 5
            //插入一个5时,将所有的5都弹出,就可以直接取到值为1的位置,确定左边界
            //若是不弹出,还要遍历过去找左边界
            while (top && a[q[top]] >= a[i]) --top;
            le[i] = q[top] + 1;
            q[++top] = i;
        }

        //将数组倒着做一遍同上操作,便可确定右边界
        top = 0;
        q[0] = n + 1;   //=n+1是因为,当队列中没有数时,所有数的右边界都是n+1-1=n
        for (int i = n; i >= 1; --i) {
            while (top && a[q[top]] >= a[i]) --top;
            ri[i] = q[top] - 1;
            q[++top] = i;

        }
//        for (int i = 1; i <= n; ++i) {
//            cout << le[i] << " " << ri[i] << endl;
//        }
        long long ans = 0;
        for (int i = 1; i <= n; ++i) {
            ans = max(ans, (long long)a[i] * (ri[i] - le[i] + 1));
        }
        printf("%lld\n", ans);
    }
    return 0;
}


你可能感兴趣的:(dp)