HDU 2795 Billboard 【线段树】

题目链接
Segment Tree, single-point update

题意

有一块h*w的告示板,要向上面贴一些广告,每张广告都想被贴得尽量靠顶端,然后再尽量靠左。现有n块尺寸分别是1*wi的广告(高度都为1)依次贴上去,问没张广告贴得位置。

分析

首先实际贴得行数肯定是min(h,n),开始没注意这个,被数据范围吓到了。然后这个问题只要记录每一行还剩下多少宽度,然后每贴一个广告就查找尽量靠左并且宽度大于等于它的。于是这就是一个单点更新的线段树,只不过查询的地方稍微改一下即可。

AC代码

//HDU 2795 Billboard
//AC 2016-10-16 15:13:32
//Segment tree
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cctype>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <set>
#include <string>
#include <map>
#include <queue>
#include <deque>
#include <list>
#include <sstream>
#include <stack>
using namespace std;

#define cls(x) memset(x,0,sizeof x)
#define inf(x) memset(x,0x3f,sizeof x)
#define neg(x) memset(x,-1,sizeof x)
#define ninf(x) memset(x,0xc0,sizeof x)
#define st0(x) memset(x,false,sizeof x)
#define st1(x) memset(x,true,sizeof x)
#define lowbit(x) x&(-x)
#define input(x) scanf("%d",&(x))
#define inputt(x,y) scanf("%d %d",&(x),&(y))
#define bug cout<<"here"<<endl;
//#pragma comment(linker, "/STACK:1024000000,1024000000")//stack expansion
//#define debug
const double PI=acos(-1.0);
const int INF=0x3f3f3f3f;//1061109567-2147483647
const long long LINF=0x3f3f3f3f3f3f3f3f;//4557430888798830399-9223372036854775807
const int maxn=200000+100;

int h,w,n;

/* 线段树 */
struct segNode
{
    int left,right;//结点对应的区间端点
    /*结点的性质*/
    int remain;
};

struct segTree
{
    segNode tree[maxn*3+10];
    /* 线段树构造函数 */
    void build(int x,int left,int right)
    {
        tree[x].left=left;
        tree[x].right=right;
        if(left==right)//只有一个元素时
        {
            tree[x].remain=w;//储存单个元素的性质
            return;
        }
        /*递归构造子树*/
        int mid=(left+right)>>1;
        build(x<<1,left,mid);
        build(x<<1|1,mid+1,right);
        /* 回溯更新当前结点依赖于子节点的性质 */
        tree[x].remain=w;
        return;
    }
    /* 线段树区间查询 */
    int querry(int x,int v)
    {
        if(tree[x].remain<v)
            return -1;
        if(tree[x].left==tree[x].right)
            return tree[x].left;
        if(tree[x<<1].remain>=v)
            return querry(x<<1,v);
        else if(tree[x<<1|1].remain>=v)
            return querry(x<<1|1,v);

    }
    /* 单点更新 */
    void change(int x,int pos,int v)
    {
        if(tree[x].left==pos&&tree[x].right==pos)//找到这个点
        {
            /* 更新内容 */
            tree[x].remain-=v;
            return;
        }
        int mid=(tree[x].left+tree[x].right)>>1;
        if(pos<=mid)
            change(x<<1,pos,v);
        else
            change(x<<1|1,pos,v);
        /* 回溯更新 */
        tree[x].remain=max(tree[x<<1].remain,tree[x<<1|1].remain);
        return;
    }
}billboard;



int main()
{
    //ios::sync_with_stdio(false);
    //cin.tie(0);
    #ifdef debug
        freopen("E:\\Documents\\code\\input.txt","r",stdin);
        freopen("E:\\Documents\\code\\output.txt","w",stdout);
    #endif
    //IO
    while(scanf("%d %d %d",&h,&w,&n)!=EOF)
    {
        int N=min(h,n);
        billboard.build(1,1,N);
        int ads=0,pos=0;
        while(n--)
        {
            input(ads);
            pos=billboard.querry(1,ads);
            printf("%d\n",pos);
            if(pos!=-1)
                billboard.change(1,pos,ads);
        }
    }
    return 0;
}
posted @ 2016-10-16 15:25  DrCarl  阅读(127)  评论(0编辑  收藏  举报