一、单调栈

定义

  单调栈,顾名思义就是说栈内的元素,按照某种方式排序下,必须是单调的。如果新入栈的元素破坏了单调性,就弹出栈内元素,知道满足单调性。它可以很方便地求出某个数的左边或者右边第一个比它大或者小的元素,而且总时间复杂度O(N)。

应用举例:poj-2559

题目大意:

  给出一个柱形统计图(histogram), 它的每个项目的宽度是1, 高度和具体问题有关。 现在编程求出在这个柱形图中的最大面积的长方形。

例如:

7 2 1 4 5 1 3 3

7表示柱形图有7个数据,分别是 2 1 4 5 1 3 3, 对应的柱形图如下,最后求出来的面积最大的图如右图所示。

单调栈/队列

思考:

  显而易见:最大矩形的高一定是某个柱形的高。那么枚举每个柱形为矩形的高度上限,令 L[x] 和 R[x] 分别代表柱形 x 的最左边和最右边第一个低于柱形x的柱形,那么答案就是 max{ h[i] * (R[i] - L[i] - 1) }。

  维护一个单调非递减栈:待处理第j个矩形

  loop:

    u := 栈顶元素;

    if(h[u] ≤ h[j]) break;

    R[u] = i;

    删除u;

   end;

  u := 栈顶元素;

  L[i] = u;

  将i入栈;

 

  为了简单起见,我们给输入的最后面分别添加一个0。

  最后遍历1~N求max{ h[i] * (R[i] - L[i] - 1) }即为答案。

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<algorithm>
 5 #include<queue>
 6 #include<cstring>
 7 #include<stack>
 8 using namespace std;
 9 
10 typedef long long LL;
11 const int N = 100010;
12 stack<int> st;
13 int h[N], L[N], R[N];
14 
15 int main()
16 {
17     int i, j, k, m, n;
18     while(scanf("%d", &n) == 1 && n)
19     {
20         for(int i=1; i<=n; i++) scanf("%d", h+i);
21         h[n+1] = 0;
22         st.push(0);
23         for(i=1; i<=n+1; i++)
24         {
25             while(h[st.top()] > h[i]) {
26                 R[st.top()] = i;
27                 st.pop();
28             }
29             L[i] = st.top();
30             st.push(i);
31         }
32         LL ans = 0;
33         for(i=1; i<=n; i++)
34             ans = max(ans, 1LL*(R[i]-L[i]-1)*h[i]);
35         printf("%I64d\n", ans);
36     }
37     return 0;
38 }
View Code

相关文章: