poj 3667 线段树区间合并

题意:有很多房间,每次客人来住的时间要连续的房间,多次操作查询。

分析:维护prefix和suffix数组来表示一段区间连续的个数

具体实现详见代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define lson   l , mid , rt << 1 
#define rson   mid + 1, r, rt << 1 | 1
using namespace std;
const int maxn = 4e5 +20;
struct InterxTree
{
	int prefix[maxn],suffix[maxn],sum[maxn],set[maxn];
	void build(int l, int r, int rt)
	{
		set[rt] = -1;
		prefix[rt] = suffix[rt] = sum[rt] = r - l + 1;
		if(l == r)
		return ;
		int mid = (l + r) >> 1;
		build(lson);
		build(rson);
	}	
	void pushdown(int rt ,int k)
	{
		if(~set[rt])
		{
			set[rt<<1] = set[rt<<1|1] = set[rt];
			prefix[rt<<1] = suffix[rt<<1] = sum[rt<<1] = set[rt] ? 0 : k - (k>>1);
			prefix[rt<<1|1] = suffix[rt<<1|1] = sum[rt<<1|1] = set[rt] ? 0 : (k>>1);
			set[rt] = -1;
		}
	}
	void maintain(int rt ,int k)
	{
		suffix[rt] = suffix[rt<<1|1];
		prefix[rt] = prefix[rt<<1];
		if(prefix[rt<<1] == k - (k>>1))
		prefix[rt] += prefix[rt<<1|1];
		if(suffix[rt<<1|1] == (k>>1))
		suffix[rt] += suffix[rt<<1];
		sum[rt] = max(suffix[rt<<1] + prefix[rt<<1|1] , max(sum[rt<<1],sum[rt<<1|1]));  
	}
	void update(int L, int R, int v, int l, int r, int rt)
	{
		if(L <= l && r <= R)
		{
			prefix[rt] = suffix[rt] = sum[rt] = v ? 0 : r - l + 1;
			set[rt] = v;
			return ;
		}
		pushdown(rt , r - l + 1);
		int mid = (l + r) >> 1;
		if(L <= mid) 
			update(L, R , v, lson);
		if(R > mid)
			update(L, R , v, rson);
		maintain(rt , r - l + 1);
	}
	int query(int v, int l, int r, int rt)
	{
		if(l == r)
		return l;
		if(set[rt] == 0)
		return l;
		int mid = (l + r) >> 1;
		if(sum[rt<<1] >= v)
			return query(v, lson);
		else if(suffix[rt<<1] + prefix[rt<<1|1] >= v)
			return mid - suffix[rt<<1] + 1;
		else return query(v, rson);
	}
}tree;
int main(void)
{
	freopen("1.txt","r",stdin);
	int n,m;
	while(~scanf("%d%d",&n,&m))
	{
		tree.build(1,n,1);
		int a,b,c;
		while(m--)
		{
			scanf("%d",&a);
			if(a==1)
			{
				scanf("%d",&b);
				if(tree.sum[1] < b)
				{
					printf("0\n");
				}
				else
				{
					int pos = tree.query(b , 1, n, 1);
					printf("%d\n",pos);
					tree.update(pos,pos + b - 1, 1, 1, n, 1);
				}
			}
			else
			{
				scanf("%d%d",&b,&c);
				tree.update(b, b + c - 1, 0, 1, n, 1);
			}
		}
	}
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值