hdu 2795 单点更新

本文介绍了一种利用线段树解决公告栏放置通知的问题。通过维护每行剩余的空间,使用线段树记录区间最大值,确保通知能被尽可能地放置在上方且左侧的位置。文章详细解释了算法的实现细节,并提供了完整的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

链接:http://acm.hdu.edu.cn/showproblem.php?pid=2795
题意:
有一个公告栏,h*m的,给定n个操作,对于每一个操作给定一个数wi,表示有一个通知的大小是1*wi的,每次对于这种操作将这个通知放在尽可能上面尽可能左边的位置中去。
思路:
有h行,将每一行初始为m,表示还有m个空位可以放,那么运用一棵线段树来记录下,行之间的区间最大值,就是可以放下的最大值。
对于每一个操作来说,尽可能的要放在上面,那么也就是这个下标要尽可能的小,所以先判断左儿子是否满足区间最大值 >= 所要求的宽度wi,如果满足的话递归的往左儿子找下去,直到找到叶子节点,更新该节点的值,减小wi;不满足再找右儿子。 先找左儿子再找右儿子保证了尽可能放在上面。
注意:
第一发RE。 然后发现此处的h是 109 ,那么按道理来说不能开下这么大的线段树,但是会发现操作的次数n是比较小的,然后想一下不管怎么样最多只需要n行的公告板就够了。因为最坏情况每个操作都是给出m长度的,填充到最后一个也才是n行。所以就只需要n就够了。
感觉要多关注,这些之间的关系,有的时候题目中是有隐含的条件的orzz 还是太年轻了。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define M 200090
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
int maxx[M<<2];
int h,m,n;
void pushup(int rt)
{
    maxx[rt] = max(maxx[rt<<1],maxx[rt<<1|1]);
}
void build(int l,int r,int rt)
{
    if(l == r)
    {
        maxx[rt] = m; //将叶子节点更新为宽度m
        return ;
    }
    int m = (l+r)>>1;
    build(lson);
    build(rson);
    pushup(rt);
}
int query(int a,int l,int r,int rt)
{
    if(l == r)
    {
        maxx[rt] -= a; //更新叶子节点
        return l; //返回序列编号
    }
    int m = (l+r)>>1;
    int ret;
    if(maxx[rt<<1] >= a) ret = query(a,lson); //左儿子的区间最大值 >= a
    else ret = query(a,rson);
    pushup(rt);
    return ret;
}
int main()
{
    while(scanf("%d%d%d",&h,&m,&n) == 3)
    {
        h = min(h,n);
        build(1,h,1);
        for(int i = 0;i < n;i++)
        {
            int a;
            scanf("%d",&a);
            if(maxx[1] < a) printf("-1\n"); //如果整个区间的最大值都小,说明不能放
            else printf("%d\n",query(a,1,h,1));
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值