题意:有一块高为h宽为w的广告牌,有n张高为1宽为wi的小广告,每次都可以在广告牌上贴广告,贴广告尽量往上贴,相同高度尽量往左贴,每次贴广告之后求该广告所在的行数,没有合适的位置就输出-1。
思路:广告牌高度维护一棵线段树,每个节点维护区间左端点l,区间右端点r,区间最大值Max,Max的值表示该区间最多空位哪一行的空位长度,与小广告的的长度进行对比,但是要优先查找左子区间(因为需要尽量往高处贴),左子区间的Max小于输入长度,再查找右子区间,如果右子区间的Max也小于输入长度,说明没有合适的位置,返回-1。
这题h,w的数据范围时1e9,但是n的范围却是200000,考虑到广告的高度是1,所以h最大其实只有200000。
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int MAX_N = 200010;
int h, w, n;
struct node {
int l, r, Max;
}tr[MAX_N * 4];
int x;
void push_up(int p) {
tr[p].Max = max(tr[p << 1].Max, tr[p << 1 | 1].Max);
}
void build(int u, int l, int r) {
tr[u].l = l, tr[u].r = r;
if (l == r) {
tr[u].Max = w;
return;
}
int mid = l + r >> 1;
build(u << 1, l, mid);
build(u << 1 | 1, mid + 1, r);
push_up(u);
}
void modify(int u, int index) {
if (tr[u].l == tr[u].r) {
tr[u].Max -= x;
return;
}
int mid = tr[u].l + tr[u].r >> 1;
if (index <= mid)modify(u << 1, index);
else modify(u << 1 | 1, index);
push_up(u);
}
int query(int u, int value) {
if (tr[u].l == tr[u].r)return tr[u].l;
int mid = tr[u].l + tr[u].r >> 1;
if (tr[u << 1].Max >= value)return query(u << 1, value);
if (tr[u << 1 | 1].Max >= value)return query(u << 1 | 1, value);
}
int main() {
while (scanf("%d%d%d", &h, &w, &n) != EOF) {
if (h > n)h = n;
build(1, 1, h);
for (int i = 1; i <= n; i++) {
scanf("%d", &x);
if (tr[1].Max < x)cout << -1 << endl;
else {
int ans = query(1, x);
cout << ans << endl;
modify(1, ans);
}
}
}
return 0;
}
来源:CSDN
作者:狂人的飞地
链接:https://blog.csdn.net/qq_43560101/article/details/104801742