hdu2795 线段树

Billboard

Time Limit: 20000/8000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 17495    Accepted Submission(s): 7388

Problem Description

At the entrance to the university, there is a huge rectangular billboard of size h*w (h is its height and w is its width). The board is the place where all possible announcements are posted: nearest programming competitions, changes in the dining room menu, and other important information.

On September 1, the billboard was empty. One by one, the announcements started being put on the billboard.

Each announcement is a stripe of paper of unit height. More specifically, the i-th announcement is a rectangle of size 1 * wi.

When someone puts a new announcement on the billboard, she would always choose the topmost possible position for the announcement. Among all possible topmost positions she would always choose the leftmost one.

If there is no valid location for a new announcement, it is not put on the billboard (that‘s why some programming contests have no participants from this university).

Given the sizes of the billboard and the announcements, your task is to find the numbers of rows in which the announcements are placed.

Input

There are multiple cases (no more than 40 cases).

The first line of the input file contains three integer numbers, h, w, and n (1 <= h,w <= 10^9; 1 <= n <= 200,000) - the dimensions of the billboard and the number of announcements.

Each of the next n lines contains an integer number wi (1 <= wi <= 10^9) - the width of i-th announcement.

Output

For each announcement (in the order they are given in the input file) output one number - the number of the row in which this announcement is placed. Rows are numbered from 1 to h, starting with the top row. If an announcement can‘t be put on the billboard, output "-1" for this announcement.

Sample Input

3 5 5
2
4
3
3
3

Sample Output

1
2
1
3
-1

题目大意:有一个广告板,高为h,宽为w,现在你要往这个广告板上放广告,每一个广告所占的面积为1*Wi,放置的规则为优先往上面放,并且同一行优先往

左边放,然后给你n个wi,依次输出这些广告所在的行数。

思路分析:刚学线段树没多久,看到这道题的分类是在线段树下,就做了一下,刚开始我是有几分蒙比的,感觉和之前做的几道题有所不同,首先是线段树的位置,

以前的线段树都是建立在n上的,而本题的线段树则应该建在h上,1-h表示行数,而节点需要维护的信息是接下来要考虑的内容,依照本题题意,维护的应该是该行

剩余的区间长度,而在子节点与根节点的关系我又有几分蒙比,后来想明白了,本题中线段树的建立主要是要提供一种高效的查找方法--二分查找,这也是本题为何

使用线段树的原因,但是本题要返回行数,则每一次查找都要到根节点,这样无疑是比较耗时的,一般会超时,但是本题的输入比较少,不超过40个例子,同时时限

放的比较宽,足足有8000ms,可以放心的用线段树了,另外以往题目往往是让返回节点储存的信息,而本题则是要返回节点的位置,这也是以后做题需要注意的地方

以后要有这种意识。对于线段树,确定好建在哪里,节点维护的信息,基本后面的都是水到渠成了。

tips:1.本题建树查找一定要先左后右这样才符合优先往上面放的题意;

2.对于线段长度,如果按题意的话,应该是h的上限10^9,但这样无疑行不通,思考一下,一共只有20w广告,如果前20w行仍然放不了这些广告,这说明什么

说明某些广告宽度>w,这样的话就算是再有其他行也没有用了,所以maxn取20w就可以,但是注意,建树是否要1-maxn?,如果h<maxn,当然不需要,但如果

 >maxn,就需要进行替换,令h=maxn,要不然会re.

代码:#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn=200000+100;
int tree[3*maxn];
int h,w;
void build(int p,int l,int r)
{
    tree[p]=w;
    if(l==r) return;
    int mid=(l+r)/2;
    build(2*p,l,mid);
    build(2*p+1,mid+1,r);
}
int find(int p,int l,int r,int b)
{
    int line;
    if(l==r){tree[p]-=b;return l;}
    int mid=(l+r)/2;
    if(tree[2*p]>=b) line=find(2*p,l,mid,b);
    else if(tree[2*p+1]>=b) line=find(2*p+1,mid+1,r,b);
    else line=-1;
    tree[p]=max(tree[2*p],tree[2*p+1]);//update
    return line;
}
int main()
{
    int n,l;
    while(scanf("%d%d%d",&h,&w,&n)!=EOF)
    {
        if(h>maxn) h=maxn;
        build(1,1,h);
        for(int i=0;i<n;i++)
        {
            scanf("%d",&l);
            printf("%d\n",find(1,1,h,l));
        }
    }
    return 0;
}

时间: 2024-11-03 05:20:18

hdu2795 线段树的相关文章

hdu2795(线段树单点更新&amp;区间最值)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2795 题意:有一个 h * w 的板子,要在上面贴 n 条 1 * x 的广告,在贴第 i 条广告时要尽量将其靠上贴,并输出其最上能贴在哪个位置: 思路:可以将每行剩余空间大小存储到一个数组中,那么对于当前 1 * x 的广告,只需找到所有剩余空间大于的 x 的行中位置最小的即可: 不过本题数据量为 2e5,直接暴力因该会 tle.可以用个线段树维护一下区间最大值,然后查询时对线段树二分即可: 代码

HDU-------(2795)Billboard(线段树区间更新)

Billboard Time Limit: 20000/8000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 10594    Accepted Submission(s): 4686 Problem Description At the entrance to the university, there is a huge rectangular billboard of s

HDU2795 Billboard 【线段树】+【单点更新】

Billboard Time Limit: 20000/8000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 9632    Accepted Submission(s): 4286 Problem Description At the entrance to the university, there is a huge rectangular billboard of s

【HDU2795】Billboard(线段树)

大意:给一个h*w的格子,然后给出多个1*w的板子往格子里面填,如果有空间尽量往上一行填满,输出行数,无法填补,则输出-1: 可以使用线段树转化问题,将每一排的格子数目放到每一个叶子节点上,然后每有一块板子,进行query查询靠左子树的第一个大于板子的叶子,进行update操作更新叶子.每个节点附权值max叶子节点即可.令一个小坑是h和w的范围是1e9,数组太大.试想如果格子高度h > 板子的个数n,那么我们只需要压缩格子到n个高度即可.所有给叶子节点的存储空间就能压缩成n的范围即1e6. 1

HDU2795 Billboard 线段树 单点更新

Problem Description At the entrance to the university, there is a huge rectangular billboard of size h*w (h is its height and w is its width). The board is the place where all possible announcements are posted: nearest programming competitions, chang

hdu2795 Billboard 线段树

题意: 给出一块h*w的广告牌,还有n张1*u的海报,海报尽量往上,左边的位置张贴,问每一张海报能贴的多高. 线段树单点修改. 注意:因为1 <= h,w <= 10^9; 1 <= n <= 200,000,但实际上,若h>n的话,最坏的情况下也只要用到前n行. 所以若h>n  则h=n 如果不加这一句,因为线段树的数组要开到h<<2这么大,又h<= 10^9,所以输入的h过大时会使开的数组过大.加了的话,就不会啦,n<<2是OK的. 1

线段树专题—HDU2795 Billboard

题意:给一块h*w广告板,然后给n个1*wi的广告条,广告条放的顺序是有限选择向上的,再优先选择左边的,对于每块广告条,输出它放的位置,如果放不下,输出-1 分析:很简单的单点更新max值的线段树,思路很好想,以广告板的每个高度建树,更新点的时候优先选择高度值小的点. 注意:比较容易出错的是 ,要注意h的范围啊1e9!!!,直接以这个高度建树肯定爆啊,这里注意到n是200000,也就是说高度最多建这么多就够了,因为上面的板都放不下了,下面肯定也用不到的. 代码: #include <iostre

hdu2795(线段树)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2795 题目大意:有一个h*w的公告牌,要在其上贴公告.现在有n个公告,每个公告的尺寸为1*wi,即高度都为1,现在依次给出n个公告的宽度wi,需要求出每个公告在广告牌所在的行数.要求:对于同一个公告尽量贴在公告牌的上方,如果高度一致,尽量贴在广告牌的左侧.如果没有合适的位置,则输出-1. 例: Sample Input 3 5 5 2 4 3 3 3 Sample Output 1 2 1 3 -1

线段树题目总结

一.单点更新 1.hdu1166 敌兵布阵:有N个兵营,每个兵营都给出了人数ai(下标从1开始),有四种命令,(1)"Addij",表示第i个营地增加j人.(2)"Sub i j",表示第i个营地减少j人.(3)"Query ij",查询第i个营地到第j个营地的总人数.(4)"End",表示命令结束.解题报告Here. 2.hdu1754 I Hate It:给你N个数,M个操作,操作分两类.(1)"QAB"