[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
#include
#include
#include
#include
#include
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]0;
        if(L<=l && r<=R){
            if(Min[rc]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]1;
        if(L<=l && r<=R){
            if(Min[lc]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;
}

你可能感兴趣的:(线段树)