hdu 2795 Billboard(线段树版)

题意:一块h*w的板子,向最左边最上方的能贴的位置贴1*k的海报n张,输出贴的行数,不能贴输出-1。


区间查询最大值。

实际上就是一个1至h的线段树,维护每个区间的最大值,找的时候优先判断左子树是否满足最大值大于k,这样保证了优先最上面,每次找到了就将这区间- k后pushup。

虽然h的范围是1到10^9,但是实际上有意义的就是n的大小,所以线段树的空间实际是200000*4.


代码:

#include <iostream>
#include <cstdio>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
int h,w;
int sum[800010];
void pushup(int rt){
    sum[rt]=max(sum[rt<<1],sum[rt<<1|1]);
}

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

int query(int k,int l,int r,int rt){
    if(l==r){
        sum[rt]-=k;
        return l;
    }
    int m=(l+r)>>1;
    int res=(sum[rt<<1]>=k?query(k,lson):query(k,rson));
    pushup(rt);
    return res;
}

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




你可能感兴趣的:(线段树)