题意:给定n个连续排列的矩形的高,矩形的宽都为1。问最大矩形覆盖。

例如:n = 7,h[i] = (2 1 4 5 1 3 3),最大覆盖为8。

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

题解:

首先可以确定,最大矩形的高一定等于某个矩形的高,宽一定等于某个矩形可以向两边最大可以延伸到的范围。

维护一个非降序的单调栈,然后依次枚举矩形的高 h[i]。

当 h[i] > top()时,说明 h[i] 向左最多可以延伸到 top() + 1,然后将 i 入栈。

当 h[i] < top()时,说明 top 向右最多可以延伸到 i - 1,为了满足栈的单调,栈顶元素要不断出栈,然后按 h[i] > top()的情况处理。

最后扫一遍,找最大的 (r[i] - l[i] + 1) * h[i],就是答案。

h[i] == top() 呢?不用管。

可以看出,对于有两个以上的矩形等价(这里的等价指的是,矩形高度相同,他们的最大延伸范围也相同)时,上面处理得到的 l[i] 和 r[i] 只有其中一个的答案会是他们最大的延伸范围,所以并不影响答案。所以维护的单调栈可以是单调不降的,也可以是单调递增的。

例如:4 4 4 4,上面求出的延伸范围是(1, 4) (2, 4) (3, 4) (4, 4)。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <stack>
using namespace std;
typedef long long LL;
const int maxn = ;
const LL INF = 1e16; int a[maxn];
LL l[maxn], r[maxn]; int main()
{
int n;
while(~scanf("%d", &n) && n)
{
for (int i = ; i <= n; i++) scanf("%d", &a[i]); stack<int> st;
st.push(), a[n+] = ;
for (int i = ; i <= n+; i++)
{
     //若是这里改成 >= 来维护单调递增的栈的话,判断应该加一个 && (a[st.top() | a[i]),防止栈空。
while(a[st.top()] > a[i])
r[st.top()] = i-, st.pop();
l[i] = st.top()+;
st.push(i);
} LL ans = -INF;
for (int i = ; i <= n; i++)
ans = max(ans, 1ll * (r[i]-l[i]+) * a[i]); printf("%lld\n", ans);
}
}

另一种做法就是笛卡尔树了。

笛卡尔树满足的条件:

1、左子树的下标 < 根节点 < 右子树

2、根节点的值是子树中所有点的最值。

可以看出,对一颗笛卡尔树中序遍历即可得到原序列。

故此题可以构造一个笛卡尔树,答案就是所有子树中 MAX(子树结点 × 根节点的值)。

笛卡尔树可以借助单调栈构建:

按照序列的顺序,每加入一个 a[i] 时,

若栈顶元素 > a[i],则不断弹出栈顶,使栈满足单调。将最后一个被弹出的做为 i 的左儿子。(因为这一段被弹出的下标都小于 i ,并且值都大于 a[i])

然后将 i 入栈,做为原本栈顶的儿子。

时间复杂度O(n)。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <stack>
using namespace std;
typedef long long LL;
const int maxn = ;
const LL INF = 1e16; int a[maxn], lson[maxn], rson[maxn], fa[maxn];
LL dp[maxn];
LL ans, tmp; LL DP(int id)
{
if (id == ) return ;
if (dp[id]) return dp[id];
dp[id] = DP(lson[id]) + DP(rson[id]) + ;
ans = max(ans, 1ll * dp[id] * a[id]);
return dp[id];
} int main()
{
int n;
while(~scanf("%d", &n) && n)
{
for (int i = ; i <= n; i++) scanf("%d", &a[i]); stack<int> st;
memset(lson, , sizeof(lson));
memset(rson, , sizeof(rson));
memset(dp, , sizeof(dp));
memset(fa, , sizeof(fa)); for (int i = ; i <= n; i++)
{
if (!st.empty() && a[st.top()] > a[i])
{
while (!st.empty() && a[st.top()] > a[i])
tmp = st.top(), st.pop();
lson[i] = tmp, fa[tmp] = i;
}
if (!st.empty()) rson[st.top()] = i, fa[i] = st.top();
st.push(i);
} ans = -INF;
for (int i = ; i <= n; i++) if (!fa[i]) DP(i); printf("%lld\n", ans);
}
}

HDU 1506 Largest Rectangle in a Histogram(单调栈、笛卡尔树)的更多相关文章

  1. HDU - 1506 Largest Rectangle in a Histogram (单调栈/笛卡尔树)

    题意:求一个直方图中最大矩形的面积. 很经典的一道问题了吧,可以用单调栈分别求出每个柱子左右两边第一个比它低的柱子(也就相当于求出了和它相连的最后一个比它高的柱子),确定每个柱子的左右边界,每个柱子的 ...

  2. hdu 1506 Largest Rectangle in a Histogram(单调栈)

                                                                                                       L ...

  3. HDU 1506 Largest Rectangle in a Histogram (dp左右处理边界的矩形问题)

    E - Largest Rectangle in a Histogram Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format: ...

  4. HDU 1506 Largest Rectangle in a Histogram set+二分

    Largest Rectangle in a Histogram Problem Description: A histogram is a polygon composed of a sequenc ...

  5. hdu 1506 Largest Rectangle in a Histogram 构造

    题目链接:HDU - 1506 A histogram is a polygon composed of a sequence of rectangles aligned at a common ba ...

  6. HDU 1506 Largest Rectangle in a Histogram(区间DP)

    题目网址:http://acm.hdu.edu.cn/showproblem.php?pid=1506 题目: Largest Rectangle in a Histogram Time Limit: ...

  7. DP专题训练之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 ...

  8. Hdu 1506 Largest Rectangle in a Histogram 分类: Brush Mode 2014-10-28 19:16 93人阅读 评论(0) 收藏

    Largest Rectangle in a Histogram Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 ...

  9. hdu 1506 Largest Rectangle in a Histogram——笛卡尔树

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=1506 关于笛卡尔树的构建:https://www.cnblogs.com/reverymoon/p/952 ...

随机推荐

  1. 在项目中导入import javax.servlet 出错解决办法

    我们有时会把别人的项目copy到自己这里进行二次开发或者参考学习,有的时候会发生下图的错误,即eclipse项目里我们导入的项目里提示HttpServletRequest 不能引用,会伴随头疼的小红叉 ...

  2. Router模块

    一.应用场景 监听浏览器地址栏URL的hash值(#后面的部分)的变化,用正则匹配出参数执行相应的JS方法.URL地址的hash部分充当业务逻辑的分发单位. 示例: <!DOCTYPE html ...

  3. cf1051F. The Shortest Statement(最短路)

    题意 题目链接 题意:给出一张无向图,每次询问两点之间的最短路,满足$m - n <= 20$ $n, m, q \leqslant 10^5$ Sol 非常好的一道题. 首先建出一个dfs树. ...

  4. meterpreter > migrate 1548

    1548  1500  explorer.exe      x86   0           LIXIULI-VCS86VR\test      C:\WINDOWS\Explorer.EXE 19 ...

  5. 如何查看与显示oracle表的分区信息

    显示分区表信息 显示数据库所有分区表的信息:DBA_PART_TABLES 显示当前用户可访问的所有分区表信息:ALL_PART_TABLES 显示当前用户所有分区表的信息:USER_PART_TAB ...

  6. IOS 线程描述

    ●什么是线程 ● 1个进程要想执行任务,必须得有线程(每1个进程至少要有1条线程) ● 线程是进程的基本执行单元,一个进程(程序)的所有任务都在线程中执行 ● 比如使用酷狗播放音乐.使用迅雷下载电影, ...

  7. IOS 导航控制器基本使用(UINavigationController代码创建方式)

    ● UINavigationController的使用步骤 ➢ 初始化UINavigationController ➢ 设置UIWindow的rootViewController为UINavigati ...

  8. POJ 3181 Dollar Dayz(递推,两个long long)

    题意:John有N美元,有价格为1~K的工具,可以买的个数不限,问1~K组合出N的方案数. f[i = 第i中工具][j = 花费为j] = 方案数. f[i][j] = sigma{ f[i-1][ ...

  9. Tarjan在图论中的应用(二)——用Tarjan来求割点与割边

    前言:\(Tarjan\) 求割点和割边建立在 \(Tarjan\)算法的基础之上,因此建议在看这篇博客之前先去学一学\(Tarjan\). 回顾\(Tarjan\)中各个数组的定义 首先,我们来回顾 ...

  10. Java环境变量搭建(Linux环境)

    1. 下载解压JDK压缩包 例如:解压到 /opt/jdk1.7.0_80 下 2. 添加环境变量到 /etc/profile 文件中 vi /etc/profile 在文件末尾追加如下内容: exp ...