Billboard HDU - 2795 线段树应用

强颜欢笑 提交于 2020-03-12 06:52:28

  题意:有一块高为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;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!