题目大意:
对于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);
}
}
}