cdoj 2015数据结构专题:G - 秋实大哥去打工

天行健,君子以自强不息。地势坤,君子以厚德载物。

天天过节的秋实大哥又要过节了,于是他要给心爱的妹子买礼物。但由于最近秋实大哥手头拮据,身为一个男人,他决定去打工!

秋实大哥来到一家广告公司。现在有 n 块矩形墙从左至右紧密排列,每一块高为 Hi ,宽为 Wi

公司要求秋实大哥找出一块最大的连续矩形区域,使得公司可以在上面贴出最大的海报。

Input

第一行包含一个整数 n ,表示矩形墙的个数。

接下来 n 行,每行有两个整数 Wi Hi ,表示第 i 块墙的宽度和高度。

1n200000 ,保证 Wi Hi 以及最后的答案 <231

Output

最大的连续矩形的面积。

Sample input and output

Sample Input Sample Output
3
3 4
1 2
3 4
14

最后所得面积的矩形的高一定是给定的某一个已有矩形的高,所以问题简化为求出以各个矩形的高为条件,能达到的最大的宽。求出后遍历一次就能找到最大的面积。

求最大宽分为两部分,向左最大宽和向右最大宽。某个矩形的最大宽即左右最大宽之和减去其本身的宽度,因为其本身宽度在计算左右宽时都加上了,计算了两次。

以求右最大宽为例,维护两个栈,一个记录矩形的编号,一个记录放入矩形的宽度。使得栈顶矩形到栈底矩形高度依次递减。向栈内依次放入矩形,当放入的矩形的高度比栈内矩形的高度低时,栈内矩形能达到的右最大宽及可通过出栈等操作获得,一直到栈内矩形的高度比放入矩形的高度低。如果此时栈内还有矩形,新加入矩形的宽度要加上出栈所有矩形的宽度,相当于记录了对于未出栈的矩形能向右延展的宽度,否则,直接入栈。最后放入完了之后要逐个出栈求出对应的右最大宽直到栈空。

#include <iostream>
#include <cstdio>
#include <stack>

using namespace std;

long long w[200005],h[200005];
int n;
long long rwid[200005],lwid[200005];

void run_r()
{
    stack <int> loc;
    stack <long long> wid;
    loc.push(0);
    wid.push(w[0]);
    for(int i = 1; i < n; i++)
    {
        while(!wid.empty() && h[i] < h[loc.top()])
        {
            int tem;
            rwid[loc.top()] = wid.top();
            tem = wid.top();
            wid.pop();
            loc.pop();
            if(!wid.empty())
                wid.top() += tem;
        }
        wid.push(w[i]);
        loc.push(i);
    }
    while(!loc.empty())
    {
        int tem;
        rwid[loc.top()] = wid.top();
        tem = wid.top();
        wid.pop();
        loc.pop();
        if(!wid.empty())
            wid.top() += tem;
    }
}

void run_l()
{
    stack <int> loc;
    stack <long long> wid;
    loc.push(n - 1);
    wid.push(w[n - 1]);
    for(int i = n - 2; i >= 0; i--)
    {
        while(!wid.empty() && h[i] < h[loc.top()])
        {
            int tem;
            lwid[loc.top()] = wid.top();
            tem = wid.top();
            wid.pop();
            loc.pop();
            if(!wid.empty())
                wid.top() += tem;
        }
        wid.push(w[i]);
        loc.push(i);
    }
    while(!loc.empty())
    {
        int tem;
        lwid[loc.top()] = wid.top();
        tem = wid.top();
        wid.pop();
        loc.pop();
        if(!wid.empty())
            wid.top() += tem;
    }
}
int main()
{
    scanf("%d", &n);
    long long suf,tem;
    for(int i = 0; i < n; i++)
        scanf("%lld%lld",&w[i], &h[i]);
    suf = 0;
    run_r();
    run_l();
    for(int i = 0; i < n; i++)
    {
        long long wid;
        wid = rwid[i] + lwid[i] - w[i];
        tem = wid * h[i];
        if(tem > suf)
            suf = tem;
    }
    printf("%lld",suf);
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值