HDU-2795Billboard+对宽度建立线段树

参考:  https://blog.csdn.net/qiqi_skystar/article/details/49073309
传送门:http://acm.hdu.edu.cn/showproblem.php?pid=2795
这个是对宽度建立线段树,每次更新这一行,一个区间的最大剩余宽度;

题目大意:有一块尺寸为h*w的矩形长板,要在上面贴1 * w【i】的海报n张。海报贴的位置要尽量靠左,如果一行能够填满就填满,最后输出的是这张海报贴的高度位置(就是在第几行)。
 
解题思路:
用高度进行建树,每一次比较宽度,在结构体里面定义一个mmax来表示最大的宽度,这个宽度在Updata()这个函数中不断地更新。一直不断的将左右儿子的最大值反馈到父亲结点。
 
特别注意:1、如果高度是5,但是有2个海报,这样我们就不需要建高度为5的树了,现在看来没有特别大的区别,但是题目中给的数据是1 <= h,w <= 10^9; 1 <= n <= 200,000~~,也就是说n最大是200000;
     2、这个题目要求输出的是你更新的位置,所以就可以少一个查找的函数。再更新的函数里面,如果这个位置更新了,就可以直接输出这个位置就OK了。
     3、一定要先比较左结点,在比较右结点。左不行在考虑右。
 
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 2e5+9;
int h,w,n;

struct node {
    int l,r;
    int mwit;
}s[maxn*4];
void initTree(int l,int r,int k)
{
    s[k].l = l,s[k].r = r;
    s[k].mwit = w;
    if(l==r)return;
    int mid = (l+r)>>1;
    initTree(l,mid,k*2);
    initTree(mid+1,r,k*2+1);
}
void update(int l,int r,int k,int x)
{
    if(l==r)
    {
        printf("%d
",l);
        s[k].mwit -= x;
        return;
    }
    int mid = (l+r)>>1;
    if(x <= s[k*2].mwit)
        update(l,mid,k*2,x);
    else update(mid+1,r,k*2+1,x);

    s[k].mwit = max(s[k*2].mwit , s[k*2+1].mwit);
}
int main(){
    while(~scanf("%d%d%d",&h,&w,&n))
    {
        if(h>n)h=n;     //这步比较重要,因为h<=1e9;而n<=2e5;由题意可得行数不会超过海报的个数;
        initTree(1,h,1);
        while(n--)
        {
            int x;
            scanf("%d",&x);
            if(x <= s[1].mwit )
            {
                update(1,h,1,x);
            }
            else puts("-1");
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/ckxkexing/p/8977542.html