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;
}