Billboard HDU - 2795 线段树点修改,求区间最大

题意

给你一个广告牌的长度和宽度,和要贴的广告数。每条广告的长度为 1 ,输入n条广告的高。输出广告所在的行数。所有的广告都靠左贴。

思路

以行数h来建树,每一个叶子结点代表一行,以数组node存放剩余宽度,初始化为广告牌的宽度。减去每次用掉的宽度,更新剩余宽度的最大值。

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=524288+10;
int node[maxn];   // 存放区间最大值(最宽的哪一行)
int h,w,n;
void bulid(int l,int r,int rt)     
{
    node[rt]=w;  // 把每一个区间初始化为 剩余的宽度,一开始没贴广告所以每个区间剩余宽度等于广告牌的宽
    if(l==r)
        return ;
    int m=(l+r)>>1;
    bulid(l,m,rt<<1);
    bulid(m+1,r,rt<<1|1);
}
int query(int x,int l,int r,int rt)
{
    if(l==r)   // 广告只能贴在叶子结点区间上   每一个叶子结点代表一行
    {
        node[rt]-=x;
        return l;  // 这个广告贴在第几行(叶子节点)
    }
    int m=(l+r)>>1;
    int res;
    if(node[rt<<1]>=x)    // 如果左子树的 剩余最大宽度 大于需要的宽度就遍历左子树,否则就遍历右子树         
                           //正好符合先贴左边的要求 
        res=query(x,l,m,rt<<1);
    else
        res=query(x,m+1,r,rt<<1|1);
    node[rt]=max(node[rt<<1],node[rt<<1|1]);  // 更新剩余最大宽度
    return res;
}
int main()
{

    int x;
    while(~scanf("%d%d%d",&h,&w,&n))
    {
        if(h>n)
            h=n;  //最多输入n行数据,当h>n时,建n行就够了
        bulid(1,h,1);   // 以行数h建树 
        for(int i=0;i<n;i++)
        {
            scanf("%d",&x);
            if(x>node[1])  //node[1]为所有区间当中的最大值
                printf("-1\n");
            else
                printf("%d\n",query(x,1,h,1));
        }
    }
    return 0;
}

这道题如果不是挂在线段树专题,我肯定不会想到用线段树。。。

猜你喜欢

转载自blog.csdn.net/qq_41837216/article/details/83210721
今日推荐