洛谷 P2894 USACO08FEB Hotel 题解

题意

第一行输入 n , m n,m n,m n n n 代表有 n n n 个房间 ( 1 ≤ n ≤ 50 , 000 ) (1\leq n \leq 50,000) (1n50,000),编号为 1 ∼ n 1 \sim n 1n,开始都为空房, m m m 表示以下有 m m m 行操作 ( 1 ≤ m < 50 , 000 ) (1\leq m < 50,000) (1m<50,000),以下每行先输入一个数 o p op op ,表示一种操作:

o p op op 1 1 1表示查询房间,再输入一个数 x x x,表示在 1 , 2 , . . . , n 1,2,...,n 1,2,...,n 房间中找到长度为 x x x 的连续空房,输出连续 x x x 个房间中左端的房间号,尽量让这个房间号最小,若找不到长度为 x x x 的连续空房,输出 0 0 0。若找得到,在这 x x x 个空房间中住上人。

若 $iop为 2 2 2表示退房,再输入两个数 x , y x,y x,y 代表房间号 x ∼ x + y − 1 x \sim x+y-1 xx+y1 退房,即让房间为空。

你需要对每个输入 1 1 1 输出对应的答案。

思路

目标是要维护区间内最长的连续的 0 0 0的数量。典型地,我们可以维护:
1. l m a : lma: lma:区间左端最大段连续 0 0 0
2. r m a : rma: rma:右端最大连续段 0 0 0
3. m a : ma: ma:区间的最大段连续 0 0 0

对于 p u s h u p pushup pushup操作就是取左子区间的 l m a lma lma、右子区间的 r m a rma rma和左子区间的 r m a rma rma加右子区间的 l m a lma lma,给一幅图就很清晰了:
在这里插入图片描述
对于该区间的 l m a lma lma,按理来说是取 l s ls ls l m a lma lma。但是如果当 l s ls ls l m a lma lma占据了整个 l s ls ls、连上了 r s rs rs l m a lma lma,就可以拓展这一贡献;对于该区间的 r m a rma rma同样如此。

void pushup(ll u)
{
	T[u].ma=max(max(T[ls].ma,T[rs].ma),T[ls].rma+T[rs].lma);
	T[u].lma=max(T[ls].lma,(T[ls].ma==T[ls].len?T[ls].ma+T[rs].lma:0ll));
	T[u].rma=max(T[rs].rma,(T[rs].ma==T[rs].len?T[rs].ma+T[ls].rma:0ll)); 
}

对于区间的入住与退房处理,可以使用懒标记节省时间,那么下面讲标记下放 p u s h d o w n pushdown pushdown怎么处理。

懒标记 t a g tag tag t a g = 1 tag=1 tag=1表示一段区间的入住,入住则整一段区间没有空房了,此时本区间和左右子区间的 l m a lma lma r m a rma rma m a ma ma都为 0 0 0

t a g = 2 tag=2 tag=2表示一段区间的退房,退房则整一段区间都是空房,此时本区间和左右子区间的 l m a lma lma r m a rma rma m a ma ma都为对应区间长度。(因此为了方便,可以再维护一个子区间长度 l e n len len

然后就是基本的标记下放,顺便把入住和退房的函数写了:

void pushdown(ll u)
{
	if(T[u].tag)
	{
		if(T[u].tag==1)
		{
			T[ls].ma=T[ls].lma=T[ls].rma=0;
			T[rs].ma=T[rs].lma=T[rs].rma=0;
		}
		else 
		{
			T[ls].ma=T[ls].lma=T[ls].rma=T[ls].len;
			T[rs].ma=T[rs].lma=T[rs].rma=T[rs].len;
		}
		T[ls].tag=T[u].tag,T[rs].tag=T[u].tag;
		T[u].tag=0;
	}
}
//book:预定 leave:退房
void book(ll u,ll l,ll r,ll ql,ll qr)
{
	if(qr<l||r<ql)return;
	if(ql<=l&&r<=qr)
	{
		T[u].ma=T[u].lma=T[u].rma=0;
		T[u].tag=1;
		return;
	}
	pushdown(u);
	ll mid=(l+r)>>1;
	if(ql<=mid)book(ls,l,mid,ql,qr);
	if(qr>mid)book(rs,mid+1,r,ql,qr);
	pushup(u);
}
void leav(ll u,ll l,ll r,ll ql,ll qr)
{
	if(qr<l||r<ql)return;
	if(ql<=l&&r<=qr)
	{
		T[u].ma=T[u].lma=T[u].rma=T[u].len;
		T[u].tag=2;
		return;
	}
	pushdown(u);
	ll mid=(l+r)>>1;
	if(ql<=mid)leav(ls,l,mid,ql,qr);
	if(qr>mid)leav(rs,mid+1,r,ql,qr);
	pushup(u); 
}

接下来是查询操作,我们要找编号最小的,能够塞得下连续 x x x个人的空房区间,向下查询需要按照编号尽量小的优先顺序分别对左子区间 l s ls ls、中间段、右子区间 r s rs rs进行查找。要注意,找的是编号尽量小而不是空余区间尽量长的。

1.如果左子区间 l s ls ls m a ma ma可以塞得下 x x x,那么就往左子区间找
2.如果中间段可以满足,即 l s ls ls r m a rma rma r s rs rs l m a lma lma可以塞得下 x x x,那么答案就是 l s ls ls r m a rma rma的开始处,可以直接算出来的,就是 m i d − T [ l s ] . r m a + 1 mid-T[ls].rma+1 midT[ls].rma+1
3.如果右子区间可以满足,与1.同理
4.剩下没有的,直接返回 0 0 0就好了

ll query(ll u,ll l,ll r,ll len)
	{
		if(l>r||T[u].ma<len)return 0;
		if(l==r)return l;
		pushdown(u);
		ll mid=(l+r)>>1;
		if(T[ls].ma>=len)return query(ls,l,mid,len);
		else if(T[ls].rma+T[rs].lma>=len)return mid-T[ls].rma+1;
		else if(T[rs].ma>=len)return query(rs,mid+1,r,len);
		else return 0;
	}

最后提醒一句,当没有满足条件的空房间区间,输出 0 0 0之后,一定要直接 c o n t i n u e continue continue,不然就会不小心把 0 0 0之后的房间填满qwq。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ls u<<1
#define rs u<<1|1
const int N=5e4+9,M=20;
ll n,m;
struct SegT
{
	struct node
	{
		ll lma,rma,ma;//左右端最大连续0,区间最多连续0
		ll tag,len;
	}T[N<<2];
	void pushup(ll u)
	{
		T[u].ma=max(max(T[ls].ma,T[rs].ma),T[ls].rma+T[rs].lma);
		T[u].lma=max(T[ls].lma,(T[ls].ma==T[ls].len?T[ls].ma+T[rs].lma:0ll));
		T[u].rma=max(T[rs].rma,(T[rs].ma==T[rs].len?T[rs].ma+T[ls].rma:0ll)); 
	}
	void pushdown(ll u)
	{
		if(T[u].tag)
		{
			if(T[u].tag==1)
			{
				T[ls].ma=T[ls].lma=T[ls].rma=0;
				T[rs].ma=T[rs].lma=T[rs].rma=0;
			}
			else 
			{
				T[ls].ma=T[ls].lma=T[ls].rma=T[ls].len;
				T[rs].ma=T[rs].lma=T[rs].rma=T[rs].len;
			}
			T[ls].tag=T[u].tag,T[rs].tag=T[u].tag;
			T[u].tag=0;
		}
	}
	void build(ll u,ll l,ll r)
	{
		T[u].ma=T[u].lma=T[u].rma=T[u].len=r-l+1;
		if(l==r)return;
		ll mid=(l+r)>>1;
		build(ls,l,mid);
		build(rs,mid+1,r);
		pushup(u);
	}
	void book(ll u,ll l,ll r,ll ql,ll qr)
	{
		if(qr<l||r<ql)return;
		if(ql<=l&&r<=qr)
		{
			T[u].ma=T[u].lma=T[u].rma=0;
			T[u].tag=1;
			return;
		}
		pushdown(u);
		ll mid=(l+r)>>1;
		if(ql<=mid)book(ls,l,mid,ql,qr);
		if(qr>mid)book(rs,mid+1,r,ql,qr);
		pushup(u);
	}
	void leav(ll u,ll l,ll r,ll ql,ll qr)
	{
		if(qr<l||r<ql)return;
		if(ql<=l&&r<=qr)
		{
			T[u].ma=T[u].lma=T[u].rma=T[u].len;
			T[u].tag=2;
			return;
		}
		pushdown(u);
		ll mid=(l+r)>>1;
		if(ql<=mid)leav(ls,l,mid,ql,qr);
		if(qr>mid)leav(rs,mid+1,r,ql,qr);
		pushup(u); 
	}
	ll query(ll u,ll l,ll r,ll len)
	{
		if(l>r||T[u].ma<len)return 0;
		if(l==r)return l;
		pushdown(u);
		ll mid=(l+r)>>1;
		if(T[ls].ma>=len)return query(ls,l,mid,len);
		else if(T[ls].rma+T[rs].lma>=len)return mid-T[ls].rma+1;
		else if(T[rs].ma>=len)return query(rs,mid+1,r,len);
		else return 0;
	}
}A;
int main()
{
	scanf("%lld%lld",&n,&m);
	A.build(1,1,n);
	while(m--)
	{
		ll op,l;
		scanf("%lld%lld",&op,&l);
		if(op==1)
		{
			ll st=A.query(1,1,n,l);
			printf("%lld\n",st);
			if(st)A.book(1,1,n,st,st+l-1);
		}
		else 
		{
			ll r;
			scanf("%lld",&r);
			r=r+l-1;
			A.leav(1,1,n,l,r);
		}
	}
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/970962.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

VS2022中.Net Api + Vue 从创建到发布到IIS

VS2022中.Net Api Vue 从创建到发布到IIS 前言一、先决条件二、创建项目三、运行项目四、增加API五、发布到IIS六、设置Vue的发布 前言 最近从VS2019 升级到了VS2022,终于可以使用官方的.Net Vue 组合了,但是使用过程中还是有很多问题,这里记录一下. 一、先决条件 Visual …

BGP分解实验·18——BGP选路原则之权重

在本地对进入的NLRI做权重设置&#xff0c;从而对过滤特定的路由进行优选。严格来说&#xff0c;权重值并不能算是路径属性&#xff0c;因为它并处传递&#xff0c;所能影响的仅仅限于本地路由器。 实验拓扑如下&#xff1a; 完成实验拓扑的基础实验&#xff0c;R1的配置如下…

正点原子ESP32S3系列开发板全面支持小智AI

什么是小智AI? 小智AI项目是由虾哥发起并开源的一个项目。该项目能帮助更多人入门AI硬件开发&#xff0c;了解如何将当下飞速发展的大语言模型应用到实际的硬件设备中。 小智AI功能如下&#xff1a; WiFi / ML307 Cat.1 4G BOOT键唤醒和打断&#xff0c;支持点击和长按两种触…

【2025最新计算机毕业设计】基于SpringBoot+Vue高校社团管理系统 【提供源码+答辩PPT+文档+项目部署】

作者简介&#xff1a;✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流。✌ 主要内容&#xff1a;&#x1f31f;Java项目、Python项目、前端项目、PHP、ASP.NET、人工智能…

探寻性能优化:如何衡量?如何决策?

目录 一、衡量指标说明 &#xff08;一&#xff09;响应时间&#xff08;Response Time&#xff09; 平均响应时间&#xff08;Average Response Time&#xff09; 百分位数响应时间&#xff08;Percentile Response Time&#xff09; &#xff08;二&#xff09;吞吐量&a…

YOLO11环境搭建CUDA12.6

1.安装CUDA和cuDNN 1.1安装CUDA 1.1.1查看当前你的电脑显卡支持的最高CUDA版本,后面的安装不能超过它 通过命令的方式查看 输入nvidia-smi 1.1.2 下载CUDA 官网地址:CUDA Toolkit Archive | NVIDIA Developer 选择cuda_12.6.3 下载完成后,如下: 安装,一直下一步即可:…

Java多线程——性能与可伸缩性

可伸缩性 当增加计算资源时&#xff08;如CPU、内存、存储容量或I/O带宽&#xff09;&#xff0c;程序的吞吐量或处理能力能相应的增加 Amdahl定理 F为必须被串行执行的部分&#xff0c;在N个处理器的机器中&#xff0c;在增加计算资源所能达到的最高加速比是 N趋于无穷大时…

Spring Boot 项目启动报错 “找不到或无法加载主类” 解决笔记

一、问题描述 在使用 IntelliJ IDEA 开发基于 Spring Boot 框架的 Java 程序时&#xff0c;原本项目能够正常启动。但在后续编写代码并重建项目后&#xff0c;再次尝试运行却出现了 “错误&#xff1a;找不到或无法加载主类 com.example.springboot.SpringbootApplication” 的…

snort3.0-ubuntu18.04 64入侵检测安装与使用

在日常生活中&#xff0c;很多人怀疑自己的手机、电脑被监控了&#xff0c;担心自己的隐私泄漏&#xff0c;实际上最佳的检测方式就是终端检测&#xff0c;也就是EDR&#xff0c;但是就是有那么多的人在网上大放厥词&#xff0c;说任何EDR杀毒软件都检测不到监控&#xff0c;毕…

Spring Cloud-Sentinel

Sentinel服务熔断与限流 Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件&#xff0c;主要以流量为切入点&#xff0c;从流量控制、流量路由、熔断降级、系统自适应保护等多个维度来帮助用户保障微服务的稳定性。 官网地址&#xff1a;home | Sentinelhttps://sen…

蓝桥与力扣刷题(230 二叉搜索树中第k小的元素)

题目&#xff1a;给定一个二叉搜索树的根节点 root &#xff0c;和一个整数 k &#xff0c;请你设计一个算法查找其中第 k 小的元素&#xff08;从 1 开始计数&#xff09;。 示例 1&#xff1a; 输入&#xff1a;root [3,1,4,null,2], k 1 输出&#xff1a;1示例 2&#xff…

安卓设备调试h5页面(调试)

1、在chrome浏览器中输入网址&#xff1a;chrome://inspect/#devices 2、设备连接usb&#xff0c;打开对应app 3、点击inspect fallback&#xff0c;打开对应调试页面

第1章大型互联网公司的基础架构——1.6 RPC服务

你可能在1.1节的引言中注意到业务服务层包括HTTP服务和RPC服务&#xff0c;两者的定位不一样。一般来说&#xff0c;一个业务场景的核心逻辑都是在RPC服务中实现的&#xff0c;强调的是服务于后台系统内部&#xff0c;所谓的“微服务”主要指的就是RPC服务&#xff1b;而HTTP服…

【NLP251】BertTokenizer 的全部 API 及 使用案例

BertTokenizer 是 Hugging Face 的 transformers 库中用于处理 BERT 模型输入的分词器类。它基于 WordPiece 分词算法&#xff0c;能够将文本分割成词汇单元&#xff08;tokens&#xff09;&#xff0c;并将其转换为 BERT 模型可以理解的格式。BertTokenizer 是 BERT 模型的核心…

SOCKET建立简单的tcp服务端与客户端通信

socket是什么 socket可以使两台机子建立连接&#xff0c;就像连接风扇与电源的插座一样&#xff0c;socket可以使服务端与客户端建立连接&#xff0c;服务端就像供电厂&#xff0c;而客户端就像用电器&#xff0c;而socket就是连接二者的插座。 建立简单的连接 如果我们想在客…

机试刷题_字符串的排列【python】

题目&#xff1a;字符串的排列 from os import dup # # 代码中的类名、方法名、参数名已经指定&#xff0c;请勿修改&#xff0c;直接返回方法规定的值即可 # # # param str string字符串 # return string字符串一维数组 # class Solution:def backtrack(self,res,state,choi…

PostgreSQL有undo表空间吗?

PostgreSQL有undo表空间吗 PostgreSQL 没有单独的 Undo 表空间&#xff0c;其事务回滚和多版本并发控制&#xff08;MVCC&#xff09;机制与 Oracle 等数据库有显著差异。 一 PostgreSQL 的 MVCC 实现 PostgreSQL 通过 多版本并发控制&#xff08;MVCC&#xff09; 管理事务…

CI/CD(二)docker-compose安装Jenkins

1、docker-compose.yml version: 3.8services:jenkins:image: jenkins/jenkins:lts # 使用官方的 Jenkins LTS 镜像container_name: jenkinsuser: root # 如果需要以 root 用户运行ports:- "8080:8080" # Jenkins Web 界面端口- "50000:50000" # 用于 Jen…

MySQL数据库(八)☞ 我是不是锁神

目录 1 全局锁的应用 2 索引对行锁的影响 3 表锁&#xff08;显式&#xff09;--表级锁 4 元数据锁 MDL(隐式)--表级锁 5 意向锁(Intention)--IS锁 IX锁--表级锁&#xff08;隐式&#xff09; 6 记录锁-(Record)-S锁 X锁 -- 行级锁 7 如何理解select ... lock in share …

rayTrace 采样

RayTrace in the rest of your life 蒙特卡洛积分 其大致内容大家可以自行去搜索&#xff0c;还是比较直观。上面的连接讲了不同的函数使用蒙特卡洛的例子 使用重要性采样 这里的重要性采样是通过pdf的值来决定的。这里有一个混淆点&#xff0c;一个是scatterPDF一个是Samp…