题目大意:
对于w*h(w <= 10^9, h <= 10^9 )的一块区域,连续摆放1*wi的木板,木板不能旋转,如果能放下就选择最靠上的位置摆放,并且输出行号,如果找不到直接输出-1。
解题思路:
这题看上去和线段树没啥关系,我一开始也挺郁闷的,还以为又选错题了。
我们先对数据范围分析一下,可以发现虽然h<=10^9,但是n<=200000,所以按照描述,我们只需关心,h<=200000的情况。
以h和n中的最小值为界,建一颗二叉树,每个节点有一个值m,表示当前这个区间内的可容纳最大宽度。随后对于每个长度为l的木板,在树中进行dfs,在满足m<=l的条件下一直找到叶子节点,叶子节点的m减去l,输出这个叶子节点代表的行,然后对树里面的数据进行一下维护。
#include <iostream> #include <cstdio> #include <cstring> using namespace std; struct node { int c; int s; int e; int m; }; int a[210000]; node tr[1000000]; int h,w,n; void build_tree(int c,int s,int e) { tr[c].c=c; tr[c].s=s; tr[c].e=e; tr[c].m=w; if (s == e) return ; build_tree(c<<1,s,(s+e)>>1); build_tree(c<<1 |1,((s+e)>>1)+1,e); } int okay; int update(int c,int l) { if (tr[c].m < l) return 0; if (okay != -1) return 0; if (tr[c].s == tr[c].e) { tr[c].m-=l; okay=tr[c].s; return 0; } if (tr[c<<1].m >= l) update(c<<1,l); if (tr[c<<1 |1].m >= l) update(c<<1 |1,l); if (okay != -1) { tr[c].m=tr[c<<1].m<tr[c<<1|1].m?tr[c<<1|1].m:tr[c<<1].m; } return 0; } int main() { int i; while (scanf("%d%d%d",&h,&w,&n) != EOF) { build_tree(1,1,n>h?h:n); for (i=1; i<=n; i++) { okay=-1; scanf("%d",a+i); update(1,a[i]); printf("%d\n",okay); } } }