zoukankan      html  css  js  c++  java
  • 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 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 = 100010;
    const LL INF = 1e16;
    
    int a[maxn];
    LL l[maxn], r[maxn];
    
    int main()
    {
        int n;
        while(~scanf("%d", &n) && n)
        {
            for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
    
            stack<int> st;
            st.push(0), a[n+1] = 0;
            for (int i = 1; i <= n+1; i++)
            {
         //若是这里改成 >= 来维护单调递增的栈的话,判断应该加一个 && (a[st.top() | a[i]),防止栈空。
    while(a[st.top()] > a[i]) r[st.top()] = i-1, st.pop(); l[i] = st.top()+1; st.push(i); } LL ans = -INF; for (int i = 1; i <= n; i++) ans = max(ans, 1ll * (r[i]-l[i]+1) * a[i]); printf("%lld ", 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 = 100010;
    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 == 0) return 0;
        if (dp[id]) return dp[id];
        dp[id] = DP(lson[id]) + DP(rson[id]) + 1;
        ans = max(ans, 1ll * dp[id] * a[id]);
        return dp[id];
    }
    
    int main()
    {
        int n;
        while(~scanf("%d", &n) && n)
        {
            for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
    
            stack<int> st;
            memset(lson, 0, sizeof(lson));
            memset(rson, 0, sizeof(rson));
            memset(dp, 0, sizeof(dp));
            memset(fa, 0, sizeof(fa));
    
            for (int i = 1; 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 = 1; i <= n; i++) if (!fa[i]) DP(i);
    
            printf("%lld
    ", ans);
        }
    }
  • 相关阅读:
    appium应用切换以及toast弹出框处理
    selenium元素定位方法之轴定位
    基于appium的常用元素定位方法
    基于appium的模拟单点或多点触屏操作
    app自动化测试初体验
    app自动化测试环境搭建之node+appium+ADT+MUMU模拟器
    linux的vi编辑器常用用法一览
    踩过了这些坑,你真的懂python基础吗?
    mysql分页查询
    Jenkins—Master/Slave模式
  • 原文地址:https://www.cnblogs.com/ruthank/p/9727928.html
Copyright © 2011-2022 走看看