hdu2755(线段树)

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

题目大意:
给定一个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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值