HDU - 2795 -- Billboard

题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=2795

树状数组做法:https://blog.csdn.net/moon_sky1999/article/details/81274345

线段树做法,复杂度O ( n log n ):

维护区间最大值,对于每次查询,如果左半段区间的最大值满足题意,就向左查询,否则向右。

代码:

#include <cstring>
#include <iostream>
#include <map>
#include <cmath>
#include <vector>
#include <string>
#include <algorithm>
#define ll long long
using namespace std;
const int maxn=2e5+10;
struct tree {
    int left, right;
    int maxm;
}c[maxn<<2];
int a[maxn];
void build(int id,int l,int r) {
    c[id].left = l;
    c[id].right = r;
    if (l == r) {
        c[id].maxm = a[l];
        return;
    }
    int mid = (l + r) >> 1;
    build(id << 1, l, mid);
    build(id << 1 | 1, mid + 1, r);
    c[id].maxm = max(c[id << 1].maxm, c[id << 1 | 1].maxm);
}
int query_max(int id,int l,int r) {
    if (c[id].left == l && c[id].right == r)return c[id].maxm;
    int mid = (c[id].left + c[id].right) >> 1;
    if (r <= mid)return query_max(id << 1, l, r);
    else if (l > mid)return query_max(id << 1 | 1, mid + 1, r);
    else return max(query_max(id << 1, l, mid), query_max(id << 1 | 1, mid + 1, r));
}
void update(int id,int pos,int v) {
    if (c[id].left == c[id].right)c[id].maxm = v;
    else {
        int mid = (c[id].left + c[id].right) >> 1;
        if (pos <= mid)update(id << 1, pos, v);
        else update(id << 1 | 1, pos, v);
        c[id].maxm = max(c[id << 1].maxm, c[id << 1 | 1].maxm);
    }
}
int query(int id,int x) {
    if (c[id].maxm < x)return -1;
    if (c[id].left == c[id].right)return c[id].left;
    else {
        if (c[id << 1].maxm >= x)return query(id << 1, x);
        else query(id << 1 | 1, x);
    }
}
int main() {
    /*ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);*/
    int h, w, n;
    while (~scanf("%d%d%d", &h, &w, &n)) {
        for (int i = 1; i <= n; ++i)
            a[i] = w;
        build(1, 1, min(h, n));
        int x;
        for (int i = 1; i <= n; ++i) {
            scanf("%d", &x);
            int t = query(1, x);
            if (t == -1) {
                printf("%d\n", t);
            } else {
                a[t] -= x;
                printf("%d\n", t);
                update(1, t, a[t]);
            }
        }
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值