【线段树求最靠前】【HDU2795】【Billboard】

题意:

有一个H*W的广告牌,当插入一个广告时(1*Wi),问最靠前的插入方式是什么


新生赛有个类似的题目,可惜当时居然没水过去。

果断用线段树做 以H为线段 建树,存[l,r]中最大的宽度,因为区间最大值满足区间和性质。


所以线段树几个要素如下:

线段:H

区间和性质:最大值


代码:

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <ctime>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <string>
#define oo 0x13131313
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define maxn 222222
using namespace std;
int h,w,n;
int tree[maxn*4];
int A[maxn];
void PushUp(int rt)
{
    tree[rt]=max(tree[rt<<1],tree[rt<<1|1]);
}
int build(int l,int r,int rt)
{
    if(l==r) {tree[rt]=w;return 0;}
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    PushUp(rt);
}

void input()
{
    for(int i=1;i<=n;i++)
    scanf("%d",&A[i]);
}
int updata(int p,int k,int l,int r,int rt)
{
    int m;
    if(l==r) {tree[rt]+=k;return 0;}
    m=(l+r)>>1;
    if(p<=m) updata(p,k,lson);
    else updata(p,k,rson);
    PushUp(rt);
}
int query(int p,int l,int r,int rt)
{
    if(p>tree[rt]) return -1;
    if(l==r) return l;
    int m=(l+r)>>1;
    if(p<=tree[rt<<1]) return query(p,lson);
    else return query(p,rson);
}
void solve()
{
    for(int i=1;i<=n;i++)
    {
        int t=query(A[i],1,h,1);
        printf("%d\n",t);
        if(t!=-1)
        {
            updata(t,-A[i],1,h,1);
        }
    }
}
void init()
{
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
}
int main()
{
   // init();
	while(scanf("%d%d%d",&h,&w,&n)!=EOF)
    {
        memset(tree,0,sizeof(tree));
        h=min(h,200000);
        build(1,h,1);
        input();
        solve();
    }
    return 0;
}


你可能感兴趣的:(【线段树求最靠前】【HDU2795】【Billboard】)