HDU-2795Billboard+对宽度建立线段树
参考: https://blog.csdn.net/qiqi_skystar/article/details/49073309
传送门:http://acm.hdu.edu.cn/showproblem.php?pid=2795
这个是对宽度建立线段树,每次更新这一行,一个区间的最大剩余宽度;
这个是对宽度建立线段树,每次更新这一行,一个区间的最大剩余宽度;
题目大意:有一块尺寸为h*w的矩形长板,要在上面贴1 * w【i】的海报n张。海报贴的位置要尽量靠左,如果一行能够填满就填满,最后输出的是这张海报贴的高度位置(就是在第几行)。
解题思路:
用高度进行建树,每一次比较宽度,在结构体里面定义一个mmax来表示最大的宽度,这个宽度在Updata()这个函数中不断地更新。一直不断的将左右儿子的最大值反馈到父亲结点。
特别注意:1、如果高度是5,但是有2个海报,这样我们就不需要建高度为5的树了,现在看来没有特别大的区别,但是题目中给的数据是1 <= h,w <= 10^9; 1 <= n <= 200,000~~,也就是说n最大是200000;
2、这个题目要求输出的是你更新的位置,所以就可以少一个查找的函数。再更新的函数里面,如果这个位置更新了,就可以直接输出这个位置就OK了。
3、一定要先比较左结点,在比较右结点。左不行在考虑右。
#include <iostream> #include <cstdio> #include <algorithm> using namespace std; const int maxn = 2e5+9; int h,w,n; struct node { int l,r; int mwit; }s[maxn*4]; void initTree(int l,int r,int k) { s[k].l = l,s[k].r = r; s[k].mwit = w; if(l==r)return; int mid = (l+r)>>1; initTree(l,mid,k*2); initTree(mid+1,r,k*2+1); } void update(int l,int r,int k,int x) { if(l==r) { printf("%d\n",l); s[k].mwit -= x; return; } int mid = (l+r)>>1; if(x <= s[k*2].mwit) update(l,mid,k*2,x); else update(mid+1,r,k*2+1,x); s[k].mwit = max(s[k*2].mwit , s[k*2+1].mwit); } int main(){ while(~scanf("%d%d%d",&h,&w,&n)) { if(h>n)h=n; //这步比较重要,因为h<=1e9;而n<=2e5;由题意可得行数不会超过海报的个数; initTree(1,h,1); while(n--) { int x; scanf("%d",&x); if(x <= s[1].mwit ) { update(1,h,1,x); } else puts("-1"); } } return 0; }
skr