hdu 2795 Billboard(线段树版)

题目链接:点击打开链接


题意:一个h*w的板子,往上贴一些1*n的海报,每次选择最上方最左方的地方贴,输出每张海报贴的行数,不能贴就输出-1


实际上就是一个1到h的线段树,每次找到最左边第一个大于n的位置,将这个位置的数减n。

本题h范围是10^9,但因为n的范围是200000,实际上h的范围也是200000,。

线段数保存的是区间最大值,查询时每次都优先看左子树满不满足,这样保证是最靠左的。


代码:

#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;
}




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