hdu 2795 Billboard 线段树

题意:

给出公告板的高和宽h,w,现在要粘贴公告(每条公告高度为1),粘贴在能粘贴的最上面的位置。给出n个公告的宽度,顺序粘贴,让你求每个公告在第几行。

分析:

n最大为200000,不可能每次顺序地遍历。我们可以用线段树来记录每一行的剩余的宽度。但是行数h最大有10^9方,不可能开这么大的数组呀。我们再看看公告条数n的范围,每一个公告条要么占据了一行,要么就贴不上去,也就是说所需要的行数最大为n,当h>n时,把n赋值给h就可以了。

这里的查询和更新都是对单点进行操作,所以可以合并到一起

query:边查询边更新

#include <bits/stdc++.h>
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
using namespace std;

const int MAXN = 200008;
int maxw[MAXN<<2];
int h,w;

void build(int l, int r, int rt)
{
    if(l == r)
    {
        maxw[rt] = w;
        return;
    }
    int m = (l + r) >> 1;
    build(lson);
    build(rson);
    maxw[rt] = max(maxw[rt<<1], maxw[rt<<1|1]);
}

int query(int wid, int l, int r, int rt)
{
    if(maxw[rt] < wid) return -1;
    if(l == r)
    {
        maxw[rt] -= wid;
        return l;
    }
    int m = (l + r) >> 1;
    int ret = query(wid, lson);
    if(ret == -1) ret = query(wid, rson);
    maxw[rt] = max(maxw[rt<<1], maxw[rt<<1|1]);
    return ret;
}

int a[MAXN];

int main()
{
//    freopen("in.txt", "r", stdin);
    int n, wid;
    while(~scanf("%d%d%d", &h, &w, &n))
    {
        if(h > n) h = n;
        build(1, h, 1);
        for(int i=0; i<n; i++)
        {
            scanf("%d", &wid);
            printf("%d
",query(wid, 1, h, 1));
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/pach/p/7349170.html