题目大意:
有多个测例(以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, 月亮的,阴历的