hdu2795Billboard

http://acm.hdu.edu.cn/showproblem.php?pid=2795

题意,一块宽w 高h的板,贴上若干宽为1的条,优先一行一行贴,贴不开换下行,问每个条所在的行数。

使用线段树,根节点表示1-h,每个节点储存的是最大值,初始每个节点都没贴,也就是w,当找到叶子节点,且有足够大的空间贴广告时,改变域值,返回。如果当前区间的最大可用空间都不够用时,即可return。如果已经找到合适的位置了,右半区间就不用再找了。每次回溯的时候,要把改变过的最大空间值MAX,层层返回,层层更新。注意到h与w的范围可以达到10的9次方,如果以h的范围来建树应该会爆内存。但是n的最大值不过是20万而已,分析一下可知n个公告最多占用布告板的高度为n。所以应该可以用n的范围来开内存,然后以min(n, h)的值作为区间范围来建树。节点存储高度编号区间的剩余可用宽度最大值就可以了。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;

const int maxn=200005;
int h,w,n;
int MAX[maxn<<2];

void build(int l,int r,int rt)
{
    MAX[rt]=w;
    if(l==r)
    return ;
    int m=(l+r)>>1;
    build(l,m,rt<<1);
    build(m+1,r,rt<<1|1);
}
int query(int x,int l,int r,int rt)
{
    if(l==r)
    {
        MAX[rt]-=x;
        return l;
    }
    int m=(l+r)>>1;
    int ret=0;
    if(x<=MAX[rt<<1]) ret=query(x,l,m,rt<<1);
    else ret=query(x,m+1,r,rt<<1|1);
    MAX[rt]=max(MAX[rt<<1],MAX[rt<<1|1]);
    return ret;
}
int main()
{
    while(scanf("%d%d%d",&h,&w,&n)!=-1)
    {
        if(h>n) h=n;
        build(1,n,1);
        while(n--)
        {
            int t;
            scanf("%d",&t);
            if(t>MAX[1])
            printf("-1\n");
            else
            printf("%d\n",query(t,1,h,1));
        }
    }
    return 0;
}
    原文作者:B树
    原文地址: https://blog.csdn.net/aonaigayiximasi/article/details/51484645
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞