类型:单调栈

传送门:>Here<

题意:给出若干宽度相同的矩形的高度(条形统计图),求最大子矩形面积

解题思路

单调栈的经典题

显然,最终的子矩形高度一定和某一个矩形相等(反证)。因此一个暴力的做法就是枚举每一个矩形,然后往两边扩散。在它左侧找到第一个高度比它小的,右侧也一样。则可以求出最大可扩散宽度,乘上高度即可以更新答案。复杂度$O(n^2)$

如果说要优化刚才的算法,也就可以优化寻找最大可扩散宽度的速度

让每一个矩形依次入栈,保存两个关键字:矩形高度,其最大左扩散宽度。保证栈内的矩形高度单调递增

我们可以得到结论:目前栈内的一个矩形$u$,在原图中从$u$开始一直到栈顶所在的矩形,高度一定都比$u$高。这就是为什么我们不需要统计栈内矩形的最大右扩散宽度,因为最大右扩散宽度就是栈顶

再回忆一下最大左扩散宽度的意义,是在它左侧的高度大于它的矩形们。这让我们又得出一个结论:目前栈内的一个矩形$u$,如果它的最大左扩散宽度大于$1$,则这些它所能扩散到的矩形一定都不在栈中。这也很容易发现,因为栈是单调递增的。或者,我们可以得到一个更形象的结论:栈内连续的两个矩形$u,v$,如果在原图中他们之间有矩形,那么这些矩形一定都高于$u,v$

因此刚才我们所说的最大左扩散宽度,其实等同于在原图中,它到栈中上一个矩形之间相隔了多少矩形

当一个新的矩形进来的时候,它会弹走若干个矩形。而栈内一个矩形实际上代表着原图中一段矩形。因此可以说是弹走了几段矩形。但是这些被弹走的矩形只不过出栈,在原图中并不会消失。因此他们所代表的的宽度不应当消失,所以我们将他们累积在新进来的这个矩形上。这也非常符合事实——这个新的矩形之所以能弹走这若干个矩形是因为自己比他们矮,因此都可以扩散到。换句话说,被弹走的这一系列矩形最多只能向右扩散到这个新矩形,因此留着它们就没有意义了

而对于任何一个要出栈的矩形,我们需要统计由它的高度所能扩散出去的最大子矩形面积。由于它的最大左扩散宽度已知,唯一需要知道的就是它的最大右扩散宽度。那么由于它在栈里,它的最大右扩散宽度也就是从它一直到最早先的栈顶之间的宽度。因此我们只需要在弹栈的过程中一路累积每个出栈矩形的最大左扩散宽度,加起来就是这一段宽度了。

另外,如果处理完了最后一个矩形以后栈依然有剩余,则应当弹完并更新答案

保证了每个矩形入栈以及出栈恰好一次,在正确性显然的条件下,复杂度$O(n)$

Code

/*By DennyQi 2018.8.18*/
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
#define r read()
#define Max(a,b) (((a)>(b)) ? (a) : (b))
#define Min(a,b) (((a)<(b)) ? (a) : (b))
using namespace std;
typedef long long ll;
#define int ll
const int MAXN = ;
const int INF = ;
inline int read(){
int x = ; int w = ; register int c = getchar();
while(c ^ '-' && (c < '' || c > '')) c = getchar();
if(c == '-') w = -, c = getchar();
while(c >= '' && c <= '') x = (x<<) + (x<<) + c - '', c = getchar();return x * w;
}
int N,H,top,cnt,ans;
int h[MAXN],w[MAXN];
#undef int
int main(){
#define int ll
for(;;){
N=r;
if(!N) break;
top = ;
ans = ;
for(int i = ; i <= N; ++i){
H=r;
if(!top || H > h[top]){
h[++top] = H;
w[top] = ;
}
else{
cnt = ;
while(top > && H <= h[top]){
cnt += w[top];
ans = Max(ans, h[top] * cnt);
--top;
}
h[++top] = H;
w[top] = cnt+;
}
}
cnt = ;
while(top > ){
cnt += w[top];
ans = Max(ans, h[top] * cnt);
--top;
}
printf("%lld\n", ans);
}
return ;
}

☆ [POJ2559] Largest Rectangle in a Histogram 「单调栈」的更多相关文章

  1. poj2559 Largest Rectangle in a Histogram(单调栈)

    Description A histogram is a polygon composed of a sequence of rectangles aligned at a common base l ...

  2. POJ2559 Largest Rectangle in a Histogram (单调栈

    Largest Rectangle in a Histogram Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 26012 ...

  3. poj 2559 Largest Rectangle in a Histogram (单调栈)

    http://poj.org/problem?id=2559 Largest Rectangle in a Histogram Time Limit: 1000MS   Memory Limit: 6 ...

  4. 题解报告:poj 2559 Largest Rectangle in a Histogram(单调栈)

    Description A histogram is a polygon composed of a sequence of rectangles aligned at a common base l ...

  5. HDU-1506 Largest Rectangle in a Histogram【单调栈】

    Description A histogram is a polygon composed of a sequence of rectangles aligned at a common base l ...

  6. Largest Rectangle in a Histogram【单调栈模板】

    Largest Rectangle in a Histogram 题目链接(点击)来源poj 2559 A histogram is a polygon composed of a sequence ...

  7. hdu_1506:Largest Rectangle in a Histogram 【单调栈】

    题目链接 对栈的一种灵活运用吧算是,希望我的注释写的足够清晰.. #include<bits/stdc++.h> using namespace std; typedef long lon ...

  8. POJ 2559 Largest Rectangle in a Histogram(单调栈)

    [题目链接] http://poj.org/problem?id=2559 [题目大意] 给出一些宽度为1的长方形下段对其后横向排列得到的图形,现在给你他们的高度, 求里面包含的最大长方形的面积 [题 ...

  9. HDU 1506 Largest Rectangle in a Histogram(单调栈、笛卡尔树)

    题意:给定n个连续排列的矩形的高,矩形的宽都为1.问最大矩形覆盖. 例如:n = 7,h[i] = (2 1 4 5 1 3 3),最大覆盖为8. Sample Input 7 2 1 4 5 1 3 ...

随机推荐

  1. 天坑之路:用js给选中文字添加样式

    前言 本例基于react,但是实际上就是用原生js做的.兼容性做到了IE9,但是按照这个思路做是可以做到IE8甚至更低的. 需求与最初的思路 当我拿到这个需求的时候以为很简单,就是可以给页面上的文章做 ...

  2. Mysql启动找不到mysql.sock文件问题(Centos7)

    刚装完Mysql5.7,将Mysql添加到开机自启.reboot之后mysql服务却没启动起来, 直接输入mysql –uroot –p ,出现如下错误,找不到mysql.sock文件.用servic ...

  3. c语言之字符输入输出和输入验证

    单字符I/O:getchar()和putchar() #include<stdio.h> int main(void) { char ch; while ((ch = getchar()) ...

  4. hana-banach定理

    1.  x1不是X除开G以外所有的空间 2.如果极大元不是全空间的话,根据前面的讨论,还可以延拓,这就和极大矛盾了

  5. redis 的使用,及如何使用redis维护数亿人的登录状态

    一.redis中几个常用的方法 redis的使用场景移步本文 select db redis 下默认有有16个表,0~15可以通过:select 2 或者 select 11这样的方式切换表 keys ...

  6. 初用Ajax

    早就有学习Ajax的想法了,但每次拿起一本Ajax的书,翻了不到百页就学不下去了,里面讲的东西实在太多了,前面讲javaScript的内容看了好 几遍都记不住,也就没心思去看后面的内容:看Ajax案例 ...

  7. Zk搭建(Zookeeper)

      第一步: 上传----解压   tar -zxvf zookeeper-3.4.5.tar.gz----                配置zk的环境变量  ----------配置源码 vim ...

  8. O(N) 求数组中最大子串和

    int MaxSubSum3(int *arr, int len) { int i; long long MaxSum = 0; long long CurSum = 0; for(int i = 0 ...

  9. C语言操作WINDOWS系统存储区数字证书相关函数详解及实例

     C语言操作WINDOWS系统存储区数字证书相关函数详解及实例 以下代码使用C++实现遍历存储区证书及使用UI选择一个证书 --使用CertOpenSystemStore打开证书存储区. --在循环中 ...

  10. Oracle RMAN备份与还原注意事项

    1 备份文件管理 如果要删除之前的备份,不要手动去目录下删除,应该在rman命令模式下使用删除命令,否则虽然在磁盘上把物理备份文件删除了,但是使用备份查看命令会一直看到已经删除的备份文件 list b ...