HDU 2795 Billboard

题目大意:

        有多个测例(以EOF结束),每个测例中都给定一个空的h × w的布告栏(h、w∈[1, 10^9]),接下来有n张布告要贴上去(1 ≤ n ≤ 200,000),每张布告高度为1,宽度为wi(1 ≤ wi ≤ 10^9),贴布告的位置首先要高,其次要靠左贴,布告按照先后顺序一个个贴上去,布告之间不能相互覆盖,但是边界可以重合,对于每张输入的布告,都要给出它所在的行号,如果没地方能贴则输出"-1",行号以1 ~ h计。

题目链接

注释代码:

/*                                              
 * Problem ID : HDU 2795 Billboard
 * Author     : Lirx.t.Una                                              
 * Language   : C                             
 * Run Time   : 2031 ms                                              
 * Run Memory : 3352 KB                                              
*/ 

#include <stdio.h>

//海报最大数量
#define    MAXN        200000

#define    LFT(T)        ( (T) << 1 )
#define    RHT(T)        ( LFT(T) | 1 )

//线段树中区间的单位是布告栏的行
//行里面存放的是这一行最右边还剩下多少宽度没有贴海报
//如果seg[i]表示的结点区间为[lft, rht]
//则seg[i]表示海报上行lft到行rht中空白宽度最大的行的空白宽度
int        seg[MAXN << 2];
int        w;//布告板的宽度

int
max( int a, int b ) {
	
    return a > b ? a : b;
}

int
query( int tree, int wi, int lft, int rht ) {//其实也有update的作用
	//查找树tree[lft, rht]中,可以把宽度为wi的海报贴在第几行
	
    int        mid;
    int        tl, tr;
    int        res;
	
	
    if ( lft == rht ) {//搜到叶子结点
		
        seg[tree] -= wi;//减掉宽度
        return lft;
    }
	
    mid = ( lft + rht ) >> 1;
    tl  = LFT(tree);
    tr  = RHT(tree);
	
    res = seg[tl] >= wi ?//如果左子树有空可以塞就现搜左子树,这样可以保证贴得最高
		  query( tl, wi, lft, mid ) ://搜左子树
		  query( tr, wi, mid + 1, rht );//搜右子树
	
    seg[tree] = max( seg[tl], seg[tr] );//最后跟新当前结点
    return res;
}

int
main() {
	
    int        h, n;//布告板的高度和海报数
    int        wi;//每张海报的宽度
    int        i;//计数变量
	
    while ( ~scanf("%d%d%d", &h, &w, &n) ) {
		
        if ( h > n ) h = n;//表示最多能贴n行,因此可以减小线段树的规模
        for ( i = 1; i < h << 2; i++ ) seg[i] = w;//初始化,每个结点的最大空白宽度都为布告板宽度
		
        while ( n-- ) {
			
            scanf("%d", &wi);
            if ( wi > seg[1] ) puts("-1");//宽度比任意一行最大空白宽度都大
            else printf("%d\n", query( 1, wi, 1, h ));
        }
    }
	
    return 0;
}
无注释代码:

#include <stdio.h>

#define    MAXN        200000

#define    LFT(T)        ( (T) << 1 )
#define    RHT(T)        ( LFT(T) | 1 )

int        seg[MAXN << 2];
int        w;

int
max( int a, int b ) {

    return a > b ? a : b;
}

int
query( int tree, int wi, int lft, int rht ) {

    int        mid;
    int        tl, tr;
    int        res;


    if ( lft == rht ) {
    
        seg[tree] -= wi;
        return lft;
    }

    mid = ( lft + rht ) >> 1;
    tl  = LFT(tree);
    tr  = RHT(tree);

    res = seg[tl] >= wi ?
          query( tl, wi, lft, mid ) :
          query( tr, wi, mid + 1, rht );

    seg[tree] = max( seg[tl], seg[tr] );
    return res;
}

int
main() {

    int        h, n;
    int        wi;
    int        i;

    while ( ~scanf("%d%d%d", &h, &w, &n) ) {
    
        if ( h > n ) h = n;
        for ( i = 1; i < h << 2; i++ ) seg[i] = w;

        while ( n-- ) {
        
            scanf("%d", &wi);
            if ( wi > seg[1] ) puts("-1");
            else printf("%d\n", query( 1, wi, 1, h ));
        }
    }

    return 0;
}
单词解释:

topmost:adj, 最高的

stripe:n, 条纹,一条

billboard:广告牌,布告板

entrance:n, 入口

booking office:n, 售票处

jump the queue:vi, 插队

shiver:n/vi, 颤抖

scare off:vt, 吓跑

chill:adj, 寒冷的

informatics:n, 信息学,情报学

camp:n, 露营

lunar:adj, 月亮的,阴历的

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值