HDU 2795 Billboard 线段树

                                       Billboard

                Time Limit: 20000/8000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
                         Total Submission(s): 27455    Accepted Submission(s): 11200

 

翻译:

        你有一张 h*w 的木板(长为h,宽为w)   现在每次给你一张  1 * wi 的纸,(长为1,宽为wi),横着贴,问你贴得上吗? 贴的上就输出行数,并把它贴上,贴不上就输出 -1 ,并且不贴它。

       贴的时候要尽量靠上靠左贴,也就是行数越小越好,行数相同,就越左越好。

 

解题思路:

       首先,这道题不是思维题(不知道谁说的思维题,害得我不敢做 Ta -_- )

       其次,我们应该想到既然 要 求行数,我们不妨把行数作为我们的区间,进行线段树操作。

      然后,我们发现这个行数太大了,10的9次方? 我的妈呀

      接着,我们看到   n<=200000  (好像经常看到的样子啊~原来是线段树的套路数据范围啊)

                 就想,一共200000 张纸,就像每行贴一张也顶多只要 200000 (20 W)行,

                                                                                    多余的咋们用不到啊,谁叫Ta要往上贴,取小就好

      于是,我们良好地确定了算法,线段树来也——

                     我们只需要知道区间上的  最大值   即可  。

                                           (查询区间最大值,若 有满足的 则减去这张纸的wide,用个全局变量保存答案-行数)

                      左儿子的编号小  (行数小  (长)      [ l,r ] 代表 l 行到 r 行)  所以我们走左子树就好

 

PS:(如果你  WA  了)

          确定行数的时候不能取  min  ,详见代码 注释掉的  第54 行  ,为什么?

 

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>

using namespace std;

inline void wprint(int x){
	if (x>9)	wprint(x/10);
	putchar(x%10+'0');
}

inline void print(int x){
	if (x<0) x=-x,putchar('-');
	wprint(x);
	putchar('\n');
}

inline int wread(){
	char c(getchar());int wans(0),flag(1);
	while (c<'0' || c>'9') {if (c=='-') flag=-1;c=getchar();}
	while (c>='0' && c<='9' ){wans=wans*10+c-'0';c=getchar();}
	return wans*=flag;
}

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

struct node{int l,r,maxn;}e[800006];
int h,w,n,T,ans;

void make_tre (int a,int l,int r){
	e[a].l=l; e[a].r=r; e[a].maxn=w;    //一开始都有w这么宽,到后面贴上了就减去宽度
	if (l==r)	{return ;}
	int mid(l+r >>1),lson(a<<1), rson(a<<1|1);
	make_tre (lson,l,mid);make_tre (rson,mid+1,r);
}

void change_max (int a,int wid){

	if (e[a].l==e[a].r){e[a].maxn-=wid; ans=e[a].l; return ;}
	int lson(a<<1),rson(a<<1|1);	
	if (e[lson].maxn>=wid)         //看左子树行不行,行就走左子树
		change_max (lson,wid);
	else if (e[rson].maxn>=wid)    //左子树不行,看右子树行不行
		change_max (rson,wid);
	else {ans=-1; return ;}         //左右子树 都没有满足条件的 宽度   ,就返回-1
	e[a].maxn = max(e[lson].maxn, e[rson].maxn);
}

int main (){
	
	while (~scanf ("%d%d%d",&h,&w,&n)){
//		T=min(k,n);
		T=h;
		if(h>200000)	T=200000;
		make_tre(1,1,T);
		while (n--){
			ans=0;                     // 保存答案
			int wid(wread());
			change_max (1,wid);
			print(ans);
		}
	}
	return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值