hdu - 2795 - Billboard(线段树)

题意:一块宽w高h的板,有n张纸条,线条高度为1,第i张纸条的宽度为wi,将这n张纸条按顺序从上到下,从左到右贴在那块板上,输出各纸条贴在了第几行,无法贴的输出-1。 (1 <= h,w <= 10^9; 1 <= n <= 200,000)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2795

——>>线段树过,将块的高度作为线段树区间,维护各结点对应的最大容纳量就好。开始建树时我直接来了个build(1, 1, h),结果是RE,我想数组没开小,又不用指针,怎么会是RE?于是换了建树方法,直接把4*maxn个结点全部赋为w,结果还是RE,我想会不会是太大了,于是来个二分测试,submit了几十次,测出了给前400021个结点赋w时,返回的都是WA,给400022以上个结点赋w时,返回的都是RE,my god!这怎么过?再看一下别人的代码,发现有个if(h > n) h = n;东东,顿悟了!h <= 10^9,如果测试数据中来个h = 10^9,查询线段树query(1, 1, h)是一定RE的!!!如果板的高度h大于纸条的张数n,即使n张纸条全部贴下,最多就占n行,即使此时h = 10^9,如果板的高度h小于等于纸条的张数n,线段树区间的右端只能是h。所以不能直接用h或者n来做线段树的右端,应选h,但当if(h > n) h = n。

#include <cstdio>
#include <algorithm>

using namespace std;

const int maxn = 200000 + 10;
int maxv[maxn<<2], w, wi;

int query(int o, int L, int R)      //查询&更新
{
    if(maxv[o] < wi) return -1;     //不满足
    if(L == R && maxv[o] >= wi)     //叶子结点满足时,更新返回
    {
        maxv[o] -= wi;
        return L;
    }
    int M = L + (R - L) / 2, ans;
    if(maxv[2*o] >= wi) ans = query(2*o, L, M);     //先左后右
    else ans = query(2*o+1, M+1, R);
    maxv[o] = max(maxv[2*o], maxv[2*o+1]);      //更新
    return ans;
}
void build(int o, int L, int R)     //建树
{
    if(L == R)
    {
        maxv[o] = w;
        return;
    }
    int M = L + (R - L) / 2;
    build(2*o, L, M);
    build(2*o+1, M+1, R);
    maxv[o] = w;
}
int main()
{
    int h, n, i;
    while(~scanf("%d%d%d", &h, &w, &n))
    {
        if(h > n) h = n;        //这句千万别少!!!直接用h来建树RE,直接用n建树WA
        build(1, 1, h);
        for(i = 1; i <= n; i++)
        {
            scanf("%d", &wi);
            printf("%d\n", query(1, 1, h));
        }
    }
    return 0;
}


你可能感兴趣的:(hdu - 2795 - Billboard(线段树))