hdu 2795 线段树

大意:给一个h*w的公告板,然后给出多个1*wi的广告往板子上贴,如果有空间尽量往上一行贴,输出行数,无法贴上,则输出-1;

思路很巧妙,将公告板每一行映射到线段树的一个叶子节点,每个节点保存该区间内剩余可用长度最大值。每次在能满足的区间里尽量向左查询,查询到立即修改,query和update合并(写线段树注意别漏了pushup)。如果没有满足的任何一行(即tree[1] < wi, tree[1]为最大值),则返回-1。注意建树时行数取小值。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 2e5 + 10;
int tree[maxn<<2];
int h, w, n;

void pushup(int root)
{
    tree[root] = max(tree[root<<1], tree[root<<1|1]);
}


void build(int cur, int b, int e)
{
    if(b == e)
        tree[cur] = w;
    else
    {
        int mid = (b + e)>>1;
        build(cur<<1, b, mid);
        build(cur<<1|1, mid + 1, e);

        pushup(cur);
    }
}

int query(int cur, int b, int e, int x)           
{
    //printf("%d %d %d\n", cur, b, e);
    if(b == e)
    {
        if(tree[cur] >= x)        
        {
            tree[cur] -= x;        
            return b;
        }
        else
        {
            return -1;
        }
    }
    else
    {
        int mid = b + e >> 1;
        int ans;
        if(x <= tree[cur << 1])
            ans = query(cur << 1, b, mid, x);
        else
            ans = query(cur << 1|1, mid + 1, e, x);

        pushup(cur);
        return ans;


    }
}

int main()
{
    while(scanf("%d%d%d", &h, &w, &n) != EOF)
    {
        h = min(h, n);
        build(1, 1, h);

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

猜你喜欢

转载自blog.csdn.net/qq_38577732/article/details/89048662