hdu2795-Billboard(经典线段树)

hdu2795-Billboard(经典线段树)


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

题目就是给你一个 H*W的公告板,按照尽量在上在左的原理摆广告,问广告摆在那一行,摆不下输出-1.

其实就是 1-H 的线段树,记录可以放下的最长长度。

H,W的范围达到10^9,可是maxn 取到 200000,为毛呢?你猜。。。

正所谓数据范围都不是白给的,大概就是这个意思了...

#include 
   
   
    
    
#include 
    
    
     
     
#define maxn 201000
int h , w , n ;
typedef struct leng
{
    int l , r ;
    int lenmax ;
}leng;
leng a[maxn*4] ;/**开小了会Runtime error,不信你改成*2*/

void init( int left , int right , int i)
{/**初始化**/
    int mid ;
    a[i].l = left ;
    a[i].r = right ;
    a[i].lenmax = w ;
    if( left == right ) return ;
    mid = ( left + right )/2 ;
    init( left , mid , 2*i ) ;
    init( mid + 1 , right , 2*i+1 ) ;
    return ;
}

int paste( int wid , int i )
{/**首先找到那个粘贴的点,记录下那个结点,为recd**/
    int recd , k , j , len , alen ;
    while( a[i].l != a[i].r )
    {

        if( a[2*i].lenmax >=wid )
        {
            i = 2 * i ;
            continue ;
        }
        else
        {
            if( a[2*i+1].lenmax >= wid )
            {
                i = 2 * i + 1 ;
                continue ;
            }
            else
            {

                return 0;
            }
        }
    }
    recd = i ;

    len = a[i].lenmax ;
    a[i].lenmax -= wid ;
    /**从最后一个点开始往上递推,没用最简单的递推,如果被改变的结点和上一层无关,就停止递推,对,就是这样**/
    while( (i/2) > 0 )
    {
        k = i%2 ;
        if( k )
        {
            j = i - 1 ;
        }
        else
        {
            j = i + 1 ;
        }
        if( len > a[j].lenmax )
        {
            len = a[i/2].lenmax;
            a[i/2].lenmax = a[i].lenmax>a[j].lenmax ? a[i].lenmax : a[j].lenmax ;
            i = i/2 ;
        }
        else
        {
            break ;
        }
    }
    return recd ;
}
int main()
{
    int i , h_ ;
    int wid , vali ;
    while( scanf("%d%d%d" , &h,&w,&n) != EOF )
    {
        if( h > maxn )
        {
            h_ = maxn;
        }
        else
        {
            h_ = h ;
        }

        init( 1 , h_ , 1) ;

        for( i = 0 ; i < n ; i++ )
        {
            scanf( "%d" , &wid ) ;
            vali = paste( wid , 1 ) ;
            if(vali)
            printf( "%d\n" , a[vali].l ) ;
            else
            printf("-1\n");
        }
    }
    return 0;
}

    
    
   
   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值