HDU 2795 billboard 线段树

题目大意:

        对于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);
        }
    }
}


你可能感兴趣的:(c,tree,Build)