hdu2795(线段树)

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

题目大意:有一个h*w的公告牌,要在其上贴公告。现在有n个公告,每个公告的尺寸为1*wi,即高度都为1,现在依次给出n个公告的宽度wi,需要求出每个公告在广告牌所在的行数。要求:对于同一个公告尽量贴在公告牌的上方,如果高度一致,尽量贴在广告牌的左侧。如果没有合适的位置,则输出-1.

例:

Sample Input
3 5 5
2
4
3
3
3
 
Sample Output
1
2
1
3
-1
 
解题思路:这个题目和ACM-ICPC 2018 南京赛区网络预赛 G Lpl and Energy-saving Lamps很类似,可以使用同一种思想。这里我们用线段树节点存储该区间内空位最大的那一行的空位长度,只要维护每个区间的最大值就可以了。然后每输入一个公告的宽度,先与树的根相比较,如果宽度大于树的根,肯定无法插入进去,所以直接输出-1,否则的话,就先与左子树相 比较,如果比它大,就查询左子树,否则查询右子树,查询之后再减去相应的长度即可。
 
然后这题有点要注意的是,树的叶子节点总个数应该是h个,然而如果h>n的话,叶子的个数应该为n个,因为多余的无意义了。
附上代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define ll long long
#define maxn 200005
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define pushup() tree[root]=max(tree[root<<1],tree[root<<1|1])
int tree[maxn<<2];
int n,h,w,x;

void build(int l,int r,int root)
{
    if(l==r)
    {
        tree[root]=w;
        return;
    }
    int mid=l+r>>1;
    build(lson);
    build(rson);
    pushup();
}
int query(int val,int l,int r,int root)
{
    if(l==r)
    {
        tree[root]-=val;
        return l;
    }
    int mid=l+r>>1;
    int ans;
    if(val<=tree[root])
    {
        if(tree[root<<1]>=val)
            ans=query(val,lson);
        else
            ans=query(val,rson);
    }
    pushup();
    return ans;
}

int main()
{
    while(~scanf("%d%d%d",&h,&w,&n))
    {
        if(h>n)
            h=n;
        build(1,h,1);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&x);
            if(x>tree[1]) 
                printf ("%d\n",-1);
            else
                printf("%d\n",query(x,1,h,1));
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/zjl192628928/p/9697146.html
今日推荐