Hotel[线段树区间合并]

本文介绍了一种使用区间树状数组解决连续房间分配与清空问题的方法。通过维护区间的最大连续空房间数量,算法可以快速判断是否能够容纳特定数量的人并确定具体位置。文章详细阐述了数据结构的设计、更新与查询操作,并提供了完整的C++代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门

题意:

1 a:询问是不是有连续长度为a的空房间,有的话住进最左边

2 a b:将[a,a+b-1]的房间清空


原文:https://blog.youkuaiyun.com/fallen_fall/article/details/12974071 

查询的时候要能直接获取区间的最大连续空房间,这样就能判断能不能连续放下这x个人,但这样还确定不了具体放哪。放的位置有三种情况1.放在左儿子那个区间。2.放在右儿子那个区间。3.放在左右儿子中间,就是占用左区间的右部分和右区间的左部分。

这样就需要用sum保存整个区间最大的连续段,lsum保存从左端开始的最大连续段,rsum保存右端开始的最大连续段

用一个标记mark表示区间状态,0:区间全空。1:区间全满。-1:当前区间已初始化,不用向下更新


#include<iostream>
#include<cstdio>
#include<algorithm>
#define N 50005
using namespace std;
struct Node{int l,r,lsum,rsum,sum,tag;}t[N<<2];
int n,m;
int read(){
	int cnt=0,f=1;char ch=0;
	while(!isdigit(ch)){ch=getchar();if(ch=='-')f=-1;}
	while(isdigit(ch)) cnt=cnt*10+(ch-'0'),ch=getchar();
	return cnt;
}
int len(int x){return t[x].r-t[x].l+1;}
void Pushup(int x){
	t[x].lsum = t[x<<1].lsum; 
	if(t[x].lsum == len(x<<1)) t[x].lsum = t[x<<1].sum + t[x<<1|1].lsum;
	t[x].rsum = t[x<<1|1].rsum;
	if(t[x].rsum == len(x<<1|1)) t[x].rsum = t[x<<1|1].sum + t[x<<1].rsum;
	t[x].sum = max(max(t[x<<1].sum , t[x<<1|1].sum) , t[x<<1].rsum+t[x<<1|1].lsum);
}
void Pushdown(int x){
	if(t[x].tag!=-1){
		t[x<<1].tag = t[x<<1|1].tag = t[x].tag;
		t[x<<1].sum = t[x<<1].lsum = t[x<<1].rsum = t[x].tag*len(x<<1);
		t[x<<1|1].sum = t[x<<1|1].lsum = t[x<<1|1].rsum = t[x].tag*len(x<<1|1);
		t[x].tag=-1;
	}
}
void build(int x,int l,int r){
	t[x].l=l , t[x].r=r , t[x].tag=-1;
	t[x].lsum = t[x].rsum = t[x].sum = r-l+1;
	if(l==r) return; 
	int mid=l+r>>1; 
	build(x<<1,l,mid),build(x<<1|1,mid+1,r);
}
int quary(int x,int val){
	if(t[x].l==t[x].r) return t[x].l;
	Pushdown(x);
	if(val<=t[x<<1].sum) return quary(x<<1,val);
	else if(val<=t[x<<1].rsum+t[x<<1|1].lsum) return ((t[x].l+t[x].r)>>1) - t[x<<1].rsum + 1;
	else return quary(x<<1|1,val);
	return 0;
}
void update(int x,int L,int R,int op){
	if(L<=t[x].l && t[x].r<=R){
		t[x].tag=op;
		t[x].sum = t[x].lsum = t[x].rsum = len(x)*op;
		return;
	}
	Pushdown(x);
	int mid=t[x].l+t[x].r>>1;
	if(L<=mid) update(x<<1,L,R,op);
	if(R>mid) update(x<<1|1,L,R,op);
	Pushup(x);
}
int main(){
	n=read(),m=read();	build(1,1,n);
	while(m--){
		int op=read();
		if(op==1){
			int x=read();
			if(t[1].sum<x){printf("0\n");continue;}
			int p=quary(1,x);
			printf("%d\n",p);
			update(1,p,p+x-1,0);
		}
		else{
			int x=read(),d=read();
			update(1,x,x+d-1,1);
		}
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FSYo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值