Billboard HDU 2795 线段树

http://acm.hdu.edu.cn/showproblem.php?pid=2795

题意:

有一块h*w的墙,往上面贴一些1*wi的海报,要求每张海报要贴在它所能贴的最高的位置,

而且在最高的位置要贴在最左边。输出每一张海报所在的行。h,w<=10e9, n<=100000

思路:

一种很容易想到的思路是这样的,对于每一张海报,我们从最开始的位置开始找一个适合

它的行,并将其贴上,这样的复杂度就是O(n^2),显然会超时。于是我们就想到优化上面

的那个算法,第一个循环是肯定不能有化了,得到每张海报的长度,可以优化的地方是第

二点,我们如何能快速地找到第一个适合它贴的位置呢,我们可以用线段树来优化它,只

需要记录一个区间的最大剩余长度就可以来判断是否能贴该海报。 

代码:

#include<stdio.h>
#include<string.h>
#define LL(a) ( (a)<<1 )
#define RR(a) ( (a)<<1|1 )
#define MAX(a, b) (a)>(b)?(a):(b)
int h ,w , n , nn;
const int MAXN = 200010 ;
int max[MAXN<<2] ;

void build(int l ,int r,  int idx){
    if(l == r){
        max[idx] = w ;
        return ;
    }
    int mid = (l + r)>>1 ;
    build(l , mid , LL(idx)) ;
    build(mid+1, r , RR(idx)) ;
    max[idx] = w ;
}

int update(int ll ,int rr , int idx , int len){
    int res ;
    if(ll == rr){
        if(max[idx] >= len)
            max[idx] -= len ;
        else    return -1 ;
        return ll ;
    }
    int mid = (ll + rr)>>1 ;
    if( max[ LL(idx) ] >= len ){
        res = update(ll,  mid , LL(idx) , len ) ;
    }
    else if( max[ RR(idx) ] >= len ){
        res = update(mid+1, rr , RR(idx) , len ) ;
    }
    else
        res = -1 ;
    max[idx] = MAX( max[ LL(idx) ] , max[ RR(idx) ] ) ;
    return res ;
}

int main(){
    int a ;
    while(scanf("%d %d %d",&h,&w,&n) == 3){
        nn = (h < n ? h : n) ;
        build(1,nn,1) ;
        for(int i=1;i<=n;i++){
            scanf("%d" ,&a);
            printf("%d\n",update(1,nn,1,a) );
        }
    }
    return 0 ;
}

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