hdu2755(线段树)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_40733911/article/details/98077855

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

扫描二维码关注公众号,回复: 7199135 查看本文章

题目大意:
给定一个hw高宽的板子,再给定n个1w高宽的广告,把广告贴到板子上,如果能贴就输出所在的row行,否则输出-1
但是,贴广告必须符合以下要求,每个广告会尽量贴 最高层,最左边的位置(如果允许的话)
看懂样例就懂题意了
解题思路:
首先如果模拟题意,直接暴力的话就是O(nn)的复杂度,肯定超时,所以我们必须用O(nlogn)或者更低复杂度的解法,那么我们就用二分的思想,就是log的复杂度,每次判断前半段后半段,是否存在可以放置的位置,如果存在优先前半段,
那么我们就可以用线段树来维护整个区间,数组里面存的就是给定区间内可以放置的最大值,那么这个问题就简化为了,区间内求是否存在大于x的值,如果存在就减去x,并且更新当前节点的max和更新父节点的max


注意h的范围很大,而n的范围较小,所以我们最多只需维护n<<2大小的数组,而不是h<<2


代码:

#include <bits/stdc++.h>

using namespace std;
const int maxn=2e5+5;
int h,w,n;
int tree[maxn<<2];
void pushUp(int rt,int l,int r)
{
    tree[rt]=max(tree[rt<<1],tree[rt<<1|1]);
}
void build(int rt,int l,int r)
{
    if(l==r)
    {
        tree[rt]=w;
        return;
    }
    int mid=(l+r)>>1;
    build(rt<<1,l,mid);
    build(rt<<1|1,mid+1,r);
    pushUp(rt,l,r);
}
int query(int rt,int l,int r,int x)
{
    int row=-1;
    if(l==r && tree[rt]>=x)
    {
        tree[rt]-=x;
        return l;
    }
    int mid=(l+r)>>1;
    if(tree[rt<<1] <x && tree[rt<<1|1] < x) return row;
    if(tree[rt<<1] >= x)
        row= query(rt<<1,l,mid,x);
    else
        row= query(rt<<1|1,mid+1,r,x);
    pushUp(rt,l,r);
    return row;
}

int main()
{
    while(scanf("%d%d%d",&h,&w,&n)==3)
    {
        if(h>n)h=n;//没有这句话就 runtime error
        int x;
        build(1,1,h);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&x);
            int row=query(1,1,h,x);
            printf("%d\n",row);
        }

    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40733911/article/details/98077855
今日推荐