[poj2082]Terrible Sets——线段树上二分(介是你从未打过的船新解法)

题目大意:

给定n个矩形在x轴上紧贴x轴依次排开,求在这n个矩形可以围成的封闭图形内的最大矩形。

思路:

Itache真的是太强了,一下子就想到了线段树做法。对于最大的矩形,不难发现,它的上界一定是某一个给定矩形的上界。反之,每一个给定矩形的上界都有可能成为最大的矩形的上界,所以我们只要依次选定一个矩形往旁边拓展就好了。但是这样的时间复杂度太高,发现要求的是左边最后一个比上界小的矩形的坐标和右边第一个比上界小的矩形的坐标,这显然是可以线段树上二分的,于是非正解 O(nlogn) O ( n log ⁡ n ) 的算法就轻松跑过了。

/*==========================
 * Author : ylsoi
 * Problem : Terrible Sets
 * Algorithm : Segment_Tree
 * Time : 2018.5.4
 * ========================*/
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<climits>
using namespace std;
void File(){
    freopen("B.in","r",stdin);
    freopen("B.out","w",stdout);
}
#define REP(i,a,b) for(register int i=a;i<=b;++i)
#define DREP(i,a,b) for(register int i=a;i>=b;--i)
#define MREP(i,x) for(register int i=beg[x];i;i=E[i].last)
#define ll long long
#define inf INT_MAX
const int maxn=50000+10;
int n,lenth[maxn],height[maxn],ans=inf;
struct Segment_Tree{
#define mid ((l+r)>>1)
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
#define lc rt<<1
#define rc rt<<1|1
    int Min[maxn<<2];
    void build(int rt,int l,int r){
        if(l==r){Min[rt]=height[l];return;}
        build(lson);build(rson);
        Min[rt]=min(Min[lc],Min[rc]);
    }
    int queryl(int rt,int l,int r,int L,int R,int x){
        if(l==r)return Min[rt]<x ? l : 0;
        if(L<=l && r<=R){
            if(Min[rc]<x)return queryl(rson,L,R,x);
            else return queryl(lson,L,R,x);
        }
        else{
            int ret=0;
            if(L<=mid)ret=max(ret,queryl(lson,L,R,x));
            if(R>=mid+1)ret=max(ret,queryl(rson,L,R,x));
            return ret;
        }
    }
    int queryr(int rt,int l,int r,int L,int R,int x){
        if(l==r)return Min[rt]<x ? l : n+1;
        if(L<=l && r<=R){
            if(Min[lc]<x)return queryr(lson,L,R,x);
            else return queryr(rson,L,R,x);
        }
        else{
            int ret=n+1;
            if(L<=mid)ret=min(ret,queryr(lson,L,R,x));
            if(R>=mid+1)ret=min(ret,queryr(rson,L,R,x));
            return ret;
        }
    }
}T;
int main(){
    File();
    int posl[maxn]={0},posr[maxn]={0};
    while(1){
        ans=-inf;
        scanf("%d",&n);
        if(n==-1)return 0;
        REP(i,1,n)scanf("%d%d",&lenth[i],&height[i]);
        REP(i,2,n)posl[i]=posl[i-1]+lenth[i-1];
        REP(i,1,n)posr[i]=posl[i]+lenth[i];
        T.build(1,1,n);
        int left,right;
        REP(i,1,n){
            left=1;right=n;
            if(i!=1)left=T.queryl(1,1,n,1,i-1,height[i])+1;
            if(i!=n)right=T.queryr(1,1,n,i+1,n,height[i])-1;
            ans=max(ans,(posr[right]-posl[left])*height[i]);
        }
        printf("%d\n",ans);
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值