POJ 3667 Hotel(线段树)

POJ 3667 Hotel

题目链接

题意:有n个房间,现在有两个操作
1、找到连续长度a的空房间,入住,要尽量靠左边,如果有输出最左边的房间标号,如果没有输出0
2、清空[a, a + b - 1]的房间

思路:线段树的区间合并,记录下左边连续最长和右边连续最长空房间,和每一段的最大值,这样pushup的时候就是进行区间合并,注意查询的时候由于是要尽量左,所以先查左孩子,在查横跨左右的,在查右孩子

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

#define lson(x) ((x<<1)+1)
#define rson(x) ((x<<1)+2)

const int N = 50005;

int n, m;

struct Node {
	int l, r, lsum, rsum, sum, sumv, lazy;
	int size() {return r - l + 1;}
	void gao(int v) {
		lazy = v;
		if (v) lsum = rsum = sum = 0;
		else lsum = rsum = sum = r - l + 1;
		sumv = l;
	}
} node[N * 4];

void pushup(int x) {
	if (node[lson(x)].lsum == node[lson(x)].size()) node[x].lsum = node[lson(x)].lsum + node[rson(x)].lsum;
	else node[x].lsum = node[lson(x)].lsum;
	if (node[rson(x)].rsum == node[rson(x)].size()) node[x].rsum = node[lson(x)].rsum + node[rson(x)].rsum;
	else node[x].rsum = node[rson(x)].rsum;
	node[x].sum = node[lson(x)].sum;
	node[x].sumv = node[lson(x)].sumv;
	if (node[x].sum < node[lson(x)].rsum + node[rson(x)].lsum) {
		node[x].sum = node[lson(x)].rsum + node[rson(x)].lsum;
		node[x].sumv = node[lson(x)].r - node[lson(x)].rsum + 1;
	}
	if (node[x].sum < node[rson(x)].sum) {
		node[x].sum = node[rson(x)].sum;
		node[x].sumv = node[rson(x)].sumv;
	}
}

void pushdown(int x) {
	if (node[x].lazy != -1) {
		node[lson(x)].gao(node[x].lazy);
		node[rson(x)].gao(node[x].lazy);
		node[x].lazy = -1;
	}
}

void build(int l, int r, int x = 0) {
	node[x].l = l; node[x].r = r; node[x].lazy = -1;
	if (l == r) {
		node[x].lsum = node[x].rsum = node[x].sum = 1;
		return;
	}
	int mid = (l + r) / 2;
	build(l, mid, lson(x));
	build(mid + 1, r, rson(x));
	pushup(x);
}

void add(int l, int r, int v, int x = 0) {
	if (node[x].l >= l && node[x].r <= r) {
		node[x].gao(v);
		return;
	}
	int mid = (node[x].l + node[x].r) / 2;
	pushdown(x);
	if (l <= mid) add(l, r, v, lson(x));
	if (r > mid) add(l, r, v, rson(x));
	pushup(x);
}

int query(int v, int x = 0) {
	if (node[x].l == node[x].r) {
		if (node[x].sum >= v) return node[x].sumv;
		return 0;
	}
	pushdown(x);
	int ans = 0;
	if (node[lson(x)].sum >= v)
		ans = query(v, lson(x));
	else if (node[lson(x)].rsum + node[rson(x)].lsum >= v) ans = node[lson(x)].r - node[lson(x)].rsum + 1;
	else if (node[rson(x)].sum >= v)
		ans = query(v, rson(x));
	pushup(x);
	return ans;
}

int main() {
	while (~scanf("%d%d", &n, &m)) {
		build(1, n);
		int op, a, b;
		while (m--) {
			scanf("%d%d", &op, &a);
			if (op == 2) {
				scanf("%d", &b);
				add(a, a + b - 1, 0);
			} else {
				int tmp = query(a);
				printf("%d\n", tmp);
				if (tmp == 0) continue;
				add(tmp, tmp + a - 1, 1);
			}
		}
	}
	return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值