【最大值线段树】【二分查找】2286. 以组为单位订音乐会的门票

本文涉及知识点

线段树 最大值线段树
二分查找算法合集

LeetCode2286. 以组为单位订音乐会的门票

一个音乐会总共有 n 排座位,编号从 0 到 n - 1 ,每一排有 m 个座椅,编号为 0 到 m - 1 。你需要设计一个买票系统,针对以下情况进行座位安排:
同一组的 k 位观众坐在 同一排座位,且座位连续 。
k 位观众中 每一位 都有座位坐,但他们 不一定 坐在一起。
由于观众非常挑剔,所以:
只有当一个组里所有成员座位的排数都 小于等于 maxRow ,这个组才能订座位。每一组的 maxRow 可能 不同 。
如果有多排座位可以选择,优先选择 最小 的排数。如果同一排中有多个座位可以坐,优先选择号码 最小 的。
请你实现 BookMyShow 类:
BookMyShow(int n, int m) ,初始化对象,n 是排数,m 是每一排的座位数。
int[] gather(int k, int maxRow) 返回长度为 2 的数组,表示 k 个成员中 第一个座位 的排数和座位编号,这 k 位成员必须坐在 同一排座位,且座位连续 。换言之,返回最小可能的 r 和 c 满足第 r 排中 [c, c + k - 1] 的座位都是空的,且 r <= maxRow 。如果 无法 安排座位,返回 [] 。
boolean scatter(int k, int maxRow) 如果组里所有 k 个成员 不一定 要坐在一起的前提下,都能在第 0 排到第 maxRow 排之间找到座位,那么请返回 true 。这种情况下,每个成员都优先找排数 最小 ,然后是座位编号最小的座位。如果不能安排所有 k 个成员的座位,请返回 false 。

示例 1:

输入:
[“BookMyShow”, “gather”, “gather”, “scatter”, “scatter”]
[[2, 5], [4, 0], [2, 0], [5, 1], [5, 1]]
输出:
[null, [0, 0], [], true, false]

解释:
BookMyShow bms = new BookMyShow(2, 5); // 总共有 2 排,每排 5 个座位。
bms.gather(4, 0); // 返回 [0, 0]
// 这一组安排第 0 排 [0, 3] 的座位。
bms.gather(2, 0); // 返回 []
// 第 0 排只剩下 1 个座位。
// 所以无法安排 2 个连续座位。
bms.scatter(5, 1); // 返回 True
// 这一组安排第 0 排第 4 个座位和第 1 排 [0, 3] 的座位。
bms.scatter(5, 1); // 返回 False
// 总共只剩下 2 个座位。

提示:

1 <= n <= 5 * 104
1 <= m, k <= 109
0 <= maxRow <= n - 1
gather 和 scatter 总 调用次数不超过 5 * 104 次。

最大值线段树

第二种方式好解决:用向量记录各排剩余座位,并用start记录最小有剩余座位的排。本轮座位分配完毕后,start++。要判断能否满足, ∑ x : 0 m a x R o w \sum_{x:0}^{maxRow} x:0maxRow 是否大于等于k。不能用前缀和,因为座位会变化,且不是一定从start开始减少,所以无法用前缀和。可用树状树状或线段树。
第一种方式,用最大值线段树。
先看[0,maxRow] 的最大值是否大于等于k,如果不是返回[]。
如果左半部分的最大值大于等于k,抛弃右半部分,不包括mid。
否则抛弃左半部分,包括mid。
故用左开右闭空间。

代码

核心代码

template<class ELE = int >
class CTreeArr
{
public:
	CTreeArr(int iSize) :m_vData(iSize + 1)
	{

	}
	void Add(int index, ELE value)
	{
		index++;
		while (index < m_vData.size())
		{
			m_vData[index] += value;
			index += index & (-index);
		}
	}
	ELE Sum(int index)
	{
		index++;
		ELE ret = 0;
		while (index)
		{
			ret += m_vData[index];
			index -= index & (-index);
		}
		return ret;
	}
	ELE Get(int index)
	{
		return Sum(index) - Sum(index - 1);
	}
private:
	vector<ELE> m_vData;
};

template<class TSave, class TRecord, TRecord RecordNull = 0>
class CLineTree
{
public:
	CLineTree(int iEleSize)
		:m_iEleSize(iEleSize), m_vArr(m_iEleSize * 4), m_vRecord(m_iEleSize * 4, RecordNull)
	{

	}
	void Update(int iLeftIndex, int iRightIndex, TRecord value)
	{
		Update(1, 1, m_iEleSize, iLeftIndex + 1, iRightIndex + 1, value);
	}
	template<class TGet>
	void Query(const TGet& oGet, int iLeftIndex, int iRightIndex)
	{
		Query(oGet, 1, 1, m_iEleSize, iLeftIndex + 1, iRightIndex + 1);
	}
private:
	virtual void OnUpdateRecord(TRecord& old, const TRecord& newRecord) = 0;
	virtual void OnUpdateParent(TSave& par, const TSave& left, const TSave& r) = 0;
	virtual void OnUpdate(TSave& save, const int& len, const TRecord& iUpdate) = 0;
	template<class TGet>
	void Query(const TGet& oGet, int iNode, int iSaveLeft, int iSaveRight, int iQueryLeft, int iQueryRight)
	{
		if ((iQueryLeft <= iSaveLeft) && (iQueryRight >= iSaveRight))
		{
			oGet(m_vArr[iNode]);
			return;
		}
		Fresh(iNode, iSaveLeft, iSaveRight);
		const int iMid = iSaveLeft + (iSaveRight - iSaveLeft) / 2;
		if (iMid >= iQueryLeft)
		{
			Query(oGet, iNode * 2, iSaveLeft, iMid, iQueryLeft, iQueryRight);
		}
		if (iMid + 1 <= iQueryRight)
		{
			Query(oGet, iNode * 2 + 1, iMid + 1, iSaveRight, iQueryLeft, iQueryRight);
		}
	}
	void Update(int iNode, int iSaveLeft, int iSaveRight, int iOpeLeft, int iOpeRight, TRecord value)
	{
		if (iNode >= m_vArr.size())
		{
			return;
		}
		if ((iOpeLeft <= iSaveLeft) && (iOpeRight >= iSaveRight))
		{
			OnUpdate(m_vArr[iNode], min(iSaveRight, iOpeRight) - max(iSaveLeft, iOpeLeft) + 1, value);
			OnUpdateRecord(m_vRecord[iNode], value);
			return;
		}
		Fresh(iNode, iSaveLeft, iSaveRight);
		const int iMid = iSaveLeft + (iSaveRight - iSaveLeft) / 2;
		if (iMid >= iOpeLeft)
		{
			Update(iNode * 2, iSaveLeft, iMid, iOpeLeft, iOpeRight, value);
		}
		if (iMid + 1 <= iOpeRight)
		{
			Update(iNode * 2 + 1, iMid + 1, iSaveRight, iOpeLeft, iOpeRight, value);
		}
		// 如果有后代,至少两个后代
		OnUpdateParent(m_vArr[iNode], m_vArr[iNode * 2], m_vArr[iNode * 2 + 1]);
	}
	void Fresh(int iNode, int iDataLeft, int iDataRight)
	{
		if (RecordNull == m_vRecord[iNode])
		{
			return;
		}
		const int iMid = iDataLeft + (iDataRight - iDataLeft) / 2;
		Update(iNode * 2, iDataLeft, iMid, iDataLeft, iMid, m_vRecord[iNode]);
		Update(iNode * 2 + 1, iMid + 1, iDataRight, iMid + 1, iDataRight, m_vRecord[iNode]);
		m_vRecord[iNode] = RecordNull;
	}
	const int m_iEleSize;
	vector<TSave> m_vArr;
	vector<TRecord> m_vRecord;
};

template<class TSave, class TRecord, TRecord RecordNull = 0>
class CMaxLineTree : public CLineTree<TSave, TRecord, RecordNull>
{
	using CLineTree< TSave, TRecord, RecordNull>::CLineTree;
	virtual void OnUpdateRecord(TRecord& old, const TRecord& newRecord) override
	{
		old = newRecord;
	}
	virtual void OnUpdateParent(TSave& par, const TSave& left, const TSave& r) override
	{
		par = max(left, r);
	}
	virtual void OnUpdate(TSave& save, const int& len, const TRecord& iUpdate) override
	{
		save = iUpdate;
	}
};

class BookMyShow {
public:
	BookMyShow(int n, int m):m_lineTree(n), m_treeArr(n), m_iM(m){
		for (int i = 0; i < n; i++) {
			m_treeArr.Add(i, m);
		}
		m_lineTree.Update(0, n - 1,m);
	}
	vector<int> gather(int k, int maxRow) {
		int iMax = 0;
		auto Get = [&iMax](int value) {
			iMax = max(iMax, value);
		};
		m_lineTree.Query(Get, 0, maxRow);
		if (iMax < k)
		{
			return {};
		}
		int left = -1, r = maxRow;
		while (r - left > 1)
		{
			const int mid = left + (r - left) / 2;
			iMax = 0;
			m_lineTree.Query(Get, 0, mid);
			if (iMax < k)
			{
				left = mid;
			}
			else
			{
				r = mid;
			}
		}
		const int cur = m_treeArr.Get(r);
		m_lineTree.Update(r, r, cur - k);
		m_treeArr.Add(r, -k);
		return { r,m_iM - cur };
	}

	bool scatter(int k, int maxRow) {
		if (m_treeArr.Sum(maxRow) < k)
		{
			return false;
		}
		while (k > 0)
		{
			const int cur = (int)m_treeArr.Get(m_iStart);
			const int use = min(cur, k);
			k -= use;
			m_treeArr.Add(m_iStart, -use);
			m_lineTree.Update(m_iStart, m_iStart, cur - use);
			if (cur == use) {
				m_iStart++;
			}
		}
		return true;
	}
	CMaxLineTree<int,int,-1> m_lineTree;
	CTreeArr<long long> m_treeArr;
	int m_iStart = 0;
	const int m_iM;
};

2023年3月

class CLineTree
{
public:
CLineTree(int iArrSize) :m_iArrSize(iArrSize), m_vData(iArrSize * 4)
{

 }
 //iIndex 从0开始
 void Modify( int iIndex, int iValue)
 {
	 Modify(1, 1, m_iArrSize, iIndex + 1, iValue);
 }
 //iNeedQueryLeft iNeedQueryRight 从0开始
 int Query(const int iNeedQueryLeft, const int iNeedQueryRight)
 {
	 return Query(1, 1, m_iArrSize, iNeedQueryLeft + 1, iNeedQueryRight + 1);
 }

protected:
int Query(const int iTreeNodeIndex, const int iRecordLeft, const int iRecordRight, const int iNeedQueryLeft, const int iNeedQueryRight)
{
if ((iNeedQueryLeft <= iRecordLeft) && (iNeedQueryRight >= iRecordRight))
{
return m_vData[iTreeNodeIndex];
}
const int iMid = (iRecordLeft + iRecordRight) / 2;
int iRet = 0;
if (iNeedQueryLeft <= iMid)
{
iRet = Query(iTreeNodeIndex * 2, iRecordLeft, iMid, iNeedQueryLeft, iNeedQueryRight);
}
if (iNeedQueryRight > iMid)
{
iRet = max(iRet, Query(iTreeNodeIndex * 2 + 1, iMid + 1, iRecordRight, iNeedQueryLeft, iNeedQueryRight));
}
return iRet;
}
void Modify(int iTreeNodeIndex, int iLeft, int iRight, int iIndex, int iValue)
{
if (iLeft == iRight)
{
m_vData[iTreeNodeIndex] = iValue;
return;
}
const int iMid = (iLeft + iRight) / 2;
if (iIndex <= iMid)
{
Modify(iTreeNodeIndex * 2, iLeft, iMid, iIndex, iValue);
}
else
{
Modify(iTreeNodeIndex * 2 + 1, iMid + 1, iRight, iIndex, iValue);
}
m_vData[iTreeNodeIndex] = max(m_vData[iTreeNodeIndex * 2], m_vData[iTreeNodeIndex * 2 + 1]);
}
const int m_iArrSize;
std::vector m_vData;
};
template
class CTreeArr
{
public:
CTreeArr(int iSize) :m_vData(iSize+1)
{

 }
 void Add(int index, T value)
 {
	 index++;
	 while (index < m_vData.size())
	 {
		 m_vData[index] += value;
		 index += index&(-index);
	 }
 }
 T Sum(int index)
 {
	 index++;
	 T ret = 0;
	 while (index )
	 {
		 ret += m_vData[index];
		 index -= index&(-index);
	 }
	 return ret;
 }

private:
vector m_vData;
};
class BookMyShow {
public:
BookMyShow(int n, int m) :m_r(n), m_c(m), m_maxLineTree(m_r), m_sumTreeArr(m_r)
{
m_vCanBuy.assign(m_r,m_c);
for (int i = 0; i < m_r; i++)
{
m_maxLineTree.Modify(i, m_c);
m_sumTreeArr.Add(i, m_c);
}
}
vector gather(int k, int maxRow) {
if (m_maxLineTree.Query(0, maxRow) < k)
{
return vector();
}
int left = -1, right = maxRow ;
while (right > left + 1)
{
int iMid = left + (right - left) / 2;
if (m_maxLineTree.Query(0, iMid) < k )
{
left = iMid;
}
else
{
right = iMid;
}
}
vector vRet;
vRet.push_back(right);
vRet.push_back(m_c - m_vCanBuy[right]);
Sell(right, k);
Fresh();
return vRet;
}
bool scatter(int k, int maxRow) {
if (m_sumTreeArr.Sum(maxRow) < k )
{
return false;
}
for (int i = m_iPreSellOutRowNum; k > 0; i++)
{
const int iSell = min(k, m_vCanBuy[i]);
Sell(i, iSell);
k -= iSell;
}
Fresh();
return true;
}
void Sell(int r,int iNum)
{
m_vCanBuy[r] -= iNum;
m_maxLineTree.Modify(r , m_vCanBuy[r]);
m_sumTreeArr.Add(r,-iNum);
}
void Fresh()
{
while ((m_iPreSellOutRowNum < m_r) && (0 == m_vCanBuy[m_iPreSellOutRowNum]))
{
m_iPreSellOutRowNum++;
}
}
const int m_r, m_c;
vector m_vCanBuy;//各行剩余的票数,由于从左向右卖。所以一定剩下最右边的。
CLineTree m_maxLineTree;//记录各行,最大值
CTreeArr m_sumTreeArr;//方便求空闲座位之后
int m_iPreSellOutRowNum =0;//[0,m_iSellOutRow)行已经卖光

};

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

相关下载

想高屋建瓴的学习算法,请下载《喜缺全书算法册》doc版
https://download.csdn.net/download/he_zhidan/88348653

我想对大家说的话
闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。

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

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

相关文章

Win10 下 git error unable to create file Invalid argument 踩坑实录

原始解决方案参看&#xff1a;https://stackoverflow.com/questions/26097568/git-pull-error-unable-to-create-file-invalid-argument 本问题解决于 2024-02-18&#xff0c;使用 git 版本 2.28.0.windows.1 解决方案 看 Git 抛出的出错的具体信息&#xff0c;比如如下都来自…

星系炸弹(蓝桥杯真题填空题)

import java.time.LocalDate; import java.time.temporal.ChronoUnit; public class BombExplosionDate { public static void main(String[] args) { // 定义贝塔炸弹的放置日期和定时天数 LocalDate placementDate LocalDate.of(2014, 11, 9); int daysToExplode 10…

【攻防世界】FlatScience

dirsearch 扫描发现四个文件 在login.php 中发现 输入 http://61.147.171.105:61912/login.php/?debug 发现源码 <?php if(isset($_POST[usr]) && isset($_POST[pw])){$user $_POST[usr];$pass $_POST[pw];$db new SQLite3(../fancy.db);$res $db->query(…

唯美首页纯静态html5引导页源码,格子化win8风格官方引导页面源码

唯美首页纯静态html5引导页源码&#xff0c;格子化win8风格官方引导页面源码&#xff0c;喜欢的朋友可以拿去使用 源码下载 唯美首页纯静态html5引导页源码

【Ubuntu20.04.6】VMWare Station 17安装Ubuntu20.04.6虚拟机系统

步骤1&#xff1a;下载Ubuntu20.04.6镜像ISO文件 Ubuntu20.04.6镜像ISO文件下载&#xff1a; https://mirrors.ustc.edu.cn/ubuntu-releases/20.04/ 步骤2&#xff1a;下载安装VMWare Station 17 下载和安装教程&#xff1a; https://blog.csdn.net/u012621175/article/deta…

C#使用Selenium驱动Chrome浏览器

1.Selenium库依赖安装 Selenium WebDriver是Selenium项目的一部分&#xff0c;用于模拟用户在Web应用程序中的交互操作。它支持多种浏览器&#xff0c;如Chrome、Firefox、IE等&#xff0c;且与各种编程语言&#xff08;如Java、Python、C#等&#xff09;兼容&#xff0c;具有…

JAVA八股--redis

JAVA八股--redis 如何保证Redis和数据库数据一致性redisson实现的分布式锁的主从一致性Redis脑裂现象及解决方案介绍I/O多路复用模型undo log 和 redo log&#xff08;没掌握MyISAM 和 InnoDB 有什么区别&#xff1f; 如何保证Redis和数据库数据一致性 关于异步通知中消息队列…

蓝桥杯-DS18B20温度传感器

一.管脚&芯片&寄存器 1.芯片 2.了解封装以及引脚的用法 3.相关寄存器 报警功能 二&#xff0c;如何使能DS18B20芯片 1.初始化芯片&比赛提供的驱动代码 比赛提供的底层驱动代码 /* # 单总线代码片段说明1. 本文件夹中提供的驱动代码供参赛选手完成程序设计参考…

Jupyterlab+内网云穿透傻瓜式教程

文章目录 Jupyterlab内网云穿透傻瓜式教程1、Miniforge安装2、Jupyter Lab安装3、Python语言服务器安装4、PowerShell 7安装5、更改jupyter lab配置6、内网穿透7、高级体验 Jupyterlab内网云穿透傻瓜式教程 1、Miniforge安装 如下图&#xff0c;以Windows安装为例&#xff0c…

记Kubernetes(k8s):访问 Prometheus UI界面:Warning: Error fetching server time

记Kubernetes&#xff08;k8s&#xff09;&#xff1a;访问 Prometheus UI界面:Warning: Error fetching server time 1、报错详情2、解决3、再次访问 PrometheusUI界面 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 1、报错详情 Warning:…

Rust 基础语法和数据类型

数据类型 Rust提供了一系列的基本数据类型&#xff0c;包括整型&#xff08;如i32、u32&#xff09;、浮点型&#xff08;如f32、f64&#xff09;、布尔类型&#xff08;bool&#xff09;和字符类型&#xff08;char&#xff09;。此外&#xff0c;Rust还提供了原生数组、元组…

什么是文档一体化?文档一体化有什么意义?

文档一体化是从文书和档案工作全局出发&#xff0c;实现从文件生成制发到归档管理的全过程控制。包括&#xff1a;文档实体生成一体化&#xff0c;文档管理一体化&#xff0c;文档信息利用一体化&#xff0c;文档规范一体化。 文档一体化的意义在于&#xff1a; 1、使档案收集完…

11-pyspark的RDD的变换与动作算子总结

目录 前言 变换算子动作算子 PySpark实战笔记系列第二篇 10-用PySpark建立第一个Spark RDD(PySpark实战笔记系列第一篇)11-pyspark的RDD的变换与动作算子总结(PySpark实战笔记系列第二篇)) 前言 一般来说&#xff0c;RDD包括两个操作算子&#xff1a; 变换&#xff08;Transf…

BUUCTF:BUU UPLOAD COURSE 1[WriteUP]

构造一句话PHP木马 <?php eval(system($_POST[shell])); ?> 利用eval函数解析$shell的值使得服务器执行system命令 eval函数是无法直接执行命令的&#xff0c;只能把字符串当作php代码解析 这里我们构造的木马是POST的方式上传&#xff0c;那就用MaxHacKBar来执行 …

【数据库】SQL简介

SQL&#xff08;Structured Query Language&#xff0c;结构化查询语言&#xff09;是一种用于管理关系型数据库管理系统&#xff08;RDBMS&#xff09;的标准化语言。它用于访问和操作数据库中的数据&#xff0c;执行各种任务&#xff0c;如插入、更新、删除和检索数据&#x…

215 基于matlab的快速跟踪算法

基于matlab的快速跟踪算法&#xff0c;提出一种简单又快速、 鲁棒性的算法&#xff0c;基于贝叶斯框架下&#xff0c;该模型 &#xff08;即图像强度和从目标位置&#xff09; 的低级功能及周边地区的统计相关性的时空关系。跟踪问题是通过计算信心地图&#xff0c;并将以最大限…

数据结构和算法:分治

分治算法 分治&#xff08;divide and conquer&#xff09;&#xff0c;全称分而治之&#xff0c;是一种非常重要且常见的算法策略。分治通常基于递归实现&#xff0c;包括“分”和“治”两个步骤。 1.分&#xff08;划分阶段&#xff09;&#xff1a;递归地将原问题分解为两个…

初学python记录:力扣1483. 树节点的第 K 个祖先

题目&#xff1a; 给你一棵树&#xff0c;树上有 n 个节点&#xff0c;按从 0 到 n-1 编号。树以父节点数组的形式给出&#xff0c;其中 parent[i] 是节点 i 的父节点。树的根节点是编号为 0 的节点。 树节点的第 k 个祖先节点是从该节点到根节点路径上的第 k 个节点。 实现…

docker搭建EFK

目录 elasticsearch1.创建网络2.拉取镜像3.创建容器如果出现启动失败&#xff0c;提示目录挂载失败&#xff0c;可以考虑如下措施 开放防火墙端口4.验证安装成功重置es密码关闭https连接创建kibana用户创建新账户给账户授权 kibana1.创建容器2.验证安装成功3.es为kibana创建用户…

金融中的数学模型

平稳时间序列 时间序列的基本统计特性&#xff0c;如均值、方差和自相关等&#xff0c;在时间上不随时间的推移而发生显著的变化。 平稳时间序列通常具有以下特征&#xff1a; 均值不随时间变化&#xff1a;序列的均值在时间上保持恒定。方差不随时间变化&#xff1a;序列的…