计蒜客习题:公告板

这篇博客探讨了蒜厂公告板问题,其中涉及如何使用线段树数据结构来解决将不同宽度的公告放置在有限空间内的最优策略。文章提供了输入格式、样例输入和输出,以及AC代码实现线段树的细节。

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

问题:

蒜厂有一个 h×w 的矩形公告板,其中 h 是高度,w 是宽度。 
现在有若干张 1×Wi 的公告, Wi 是宽度,公告只能横着放,即高度为 1 的边垂直于水平面,且不能互相有重叠,每张公告都要求尽可能的放在最上面的合法的位置上。 
若可以放置,输出每块可放置的位置的行号;若不存在,输出 −1。行号由上至下分别为 1,2,…,h。 

输入格式 
第一行三个整数 h,w,n (1≤h,w≤10^9;1≤n≤200,000) 。 
接下来 n 行,每行一个整数 Wi(1≤Wi≤109) 。 


输出格式 
输出n 行,一行一个整数。


样例输入:

3 5 5
2
4
3
3
3
1
2
3
4
5
6
样例输出

1
2
1
3
-1


AC代码:线段树

#include<bits/stdc++.h>
using namespace std;

int s[1000010 * 5];
int h,w,n;

void up(int p){
    s[p] = max(s[p * 2],s[p * 2 + 1]);
}

void BuildTree(int p,int l,int r,int x){
    if(l == r){
        s[p] = x;
        return ;
    }
    int mid = (l + r) / 2;
    if(l <= mid){
        BuildTree(p * 2,l,mid,x);
    }
    if(r > mid){
        BuildTree(p * 2 + 1,mid + 1,r,x);
    }
    up(p);
}

void modify(int p,int l,int r,int x,int c){
    if(l == r){
        s[p] += c;
        return ;
    }
    int mid = (l + r) / 2;
    if(x <= mid){
        modify(p * 2,l,mid,x,c);
    }
    else{
        modify(p * 2 + 1,mid + 1,r,x,c);
    }
    up(p);
}

int query(int p,int l,int r,int x,int y){
    if(x <= l && y >= r){
        return s[p];  
    }
    int mid = (l + r) / 2;
    int res = 0;
    if(x <= mid){
        res = max(res,query(p * 2,l,mid,x,y));
    }
    if(y > mid){
        res = max(res,query(p * 2 + 1,mid + 1,r,x,y));
    }
    return res;
}

void getVal(int p,int l,int r,int x){
    while(l < r){
        int mid = (l + r) / 2;
        if(x <= query(1,1,h,l,mid)){
            r = mid;
        }
        else if(x <= query(1,1,h,mid + 1,r)){
            l = mid + 1;
        }
        else{
            break;
        }
    }
    if(l == r){
        modify(1,1,h,l,-x);
        printf("%d\n",l);
    }
    else{
        printf("-1\n");
    }
}

int main(){
    scanf("%d%d%d",&h,&w,&n);
    BuildTree(1,1,h,w);
    for(int i=1;i<=n;++i){
        int x;
        scanf("%d",&x);
        getVal(1,1,h,x);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值