Hotel--线段树区间合并模板题

题目链接:https://vjudge.net/problem/POJ-3667

题目大意

有n个车位,一开始全是空的。m个要求,1 k,表示有k辆车要停,且位置要连续,找到编号最小的位置输出,如果停不下,就输出0;2 x k,表示从x位置开始,有连续k辆车开走。

分析

1代表有空位,0代表没有空位。tr[m].left代表从左端点向右,连续1的区间长度,tr[m].right代表从右端点向左连续1的区间长度,tr[m].all代表整个区间内最长连续1的区间长度。

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 50010;
int n, m;
struct node{
	int l, r, left, right, all, lazy;
}tr[N<<2];
void pushup(int m)
{
	tr[m].left = tr[m<<1].left;
	tr[m].right = tr[m<<1|1].right;
	if(tr[m<<1].all == tr[m<<1].r - tr[m<<1].l + 1)
		tr[m].left += tr[m<<1|1].left;
	if(tr[m<<1|1].all == tr[m<<1|1].r - tr[m<<1|1].l + 1)
		tr[m].right += tr[m<<1].right;
	tr[m].all = max(tr[m<<1].right + tr[m<<1|1].left, max(tr[m<<1].all, tr[m<<1|1].all));
}
void pushdown(int m)
{
	if(tr[m].lazy != -1)
	{
		int val = (tr[m<<1].r - tr[m<<1].l + 1) * tr[m].lazy;
		tr[m<<1].left = tr[m<<1].right = tr[m<<1].all = val;
		tr[m<<1].lazy = tr[m].lazy;
		
		val = (tr[m<<1|1].r - tr[m<<1|1].l + 1) * tr[m].lazy;
		tr[m<<1|1].left = tr[m<<1|1].right = tr[m<<1|1].all = val;
		tr[m<<1|1].lazy = tr[m].lazy;
		
		tr[m].lazy = -1;
	}
}
void build(int m, int l, int r)
{
	tr[m].l = l;
	tr[m].r = r;
	tr[m].lazy = -1;
	tr[m].left = tr[m].right = tr[m].all = (r - l + 1);
	if(l == r) return ;
	int mid = (l + r) >> 1;
	build(m<<1, l, mid);
	build(m<<1|1, mid + 1, r);
}
void updata(int m, int l, int r, int val)
{
	if(tr[m].l == l && tr[m].r == r)
	{
		tr[m].lazy = val;
		tr[m].left = tr[m].right = tr[m].all = (r - l + 1) * val;
		return ;
	}
	pushdown(m);
	int mid = (tr[m].l + tr[m].r) >> 1;
	if(r <= mid)
		updata(m<<1, l, r, val);
	else if(l > mid)
		updata(m<<1|1, l, r, val);
	else
	{
		updata(m<<1, l, mid, val);
		updata(m<<1|1, mid + 1, r, val);
	}
	pushup(m);
}
int query(int m, int len)
{
	if(tr[m].l == tr[m].r) return tr[m].l;
	pushdown(m);
	if(tr[m<<1].all >= len)
		return query(m<<1, len);
	else if(tr[m<<1].right + tr[m<<1|1].left >= len)
		return tr[m<<1].r - tr[m<<1].right + 1;
	else
		return query(m<<1|1, len);
}
int main()
{
	while(~scanf("%d %d", &n, &m))
	{
		build(1, 1, n);
		int op;
		while(m--)
		{
			scanf("%d", &op);
			if(op == 1)
			{
				int k;
				scanf("%d", &k);
				if(tr[1].all < k)
					printf("0\n");
				else
				{
					int ans = query(1, k);
					printf("%d\n", ans);
					updata(1, ans, ans + k - 1, 0);
				}
			}
			else
			{
				int x, k;
				scanf("%d %d", &x, &k);
				updata(1, x, x + k - 1, 1);
			}
		}
	}
	return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值