hdu-2795-Billboard- 线段树-单点

题目大意:一个h*w的公告牌,要在其上贴公告。 输入的是1*wi的w值,这些是公告的尺寸接下来要满足的条件有:1、尽量往上,同一高度尽量靠左。2、求第n个广告所在的行数。3、没有合适的位置贴了则输出-1。


用线段树实现,节点存的是每一行剩余的空位,查找用的是二分的思想,每次在区间里查找第一个大于等于val值的位置。

先查左子区间是否存在大于等于val值,如果是则进入左子区间查询,否则,再去判断右区间

一直二分直到l==r,返回l下标即是 第一个大于等于val值的位置。 



#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <iostream>
using namespace std;

const long long maxn = 200005;
struct tree
{
    __int64 st_max[maxn*4];
    void init()
    {
        memset(st_max,0,sizeof(st_max));
    }
    void pushup(__int64 rt)
    {
        st_max[rt]=max(st_max[rt<<1],st_max[rt<<1|1]);
    }
    void update(__int64 l,__int64 r,__int64 rt,__int64 num,__int64 val)
    {
        if (l==r&&r==num)
        {
            st_max[rt]+=val;
            return ;
        }
        __int64 m=(l+r)>>1;
        if (num<=m)
            update(l,m,rt<<1,num,val);
        else
            update(m+1,r,rt<<1|1,num,val);
        pushup(rt);
    }
    __int64 query(__int64 val,__int64 l,__int64 r,__int64 rt) //查询大于等于val的第一个位置
    {
        if (r==l)
        {
            return l;
        }
        __int64 mid=(l+r)>>1;
        if (st_max[rt<<1]>=val)
            return query(val,l,mid,rt<<1);
        if (st_max[rt<<1|1]>=val)
            return query(val,mid+1,r,rt<<1|1);
        return -1;
    }
};
tree tp;
int main(  )
{
    __int64 i;
    __int64 x;
    __int64 n,h,w;
    __int64 cun=0;
    while(scanf("%I64d %I64d %I64d",&h,&w,&n)!=EOF)
    {
        tp.init();
        if (h>n) h=n;
        for (i=1; i<=h; i++)
            tp.update(1,h,1,i,w);
        for (i=1; i<=n; i++)
        {
            scanf("%I64d",&x);
            __int64 ret=tp.query(x,1,h,1);
            if (x>tp.st_max[1]) printf("-1\n");
            else
            {
                    printf("%I64d\n",ret);
                        tp.update(1,h,1,ret,-x);
            }
        }
    }
    return 0;
}


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