线段树区间合并(poj 3667 hotel)

题目链接

 题意:

有一家酒店,又一排n个房间,一共m个询问,如果输入操作为1,接下来再输入一个a,表示来了一群a个人,希望能住在连续的a间房间,如果有连续n间房,输出最左边的连续的a间房间最左边的那个房间,如果没有输出0

如果输入操作为2,接下来会有两个数a,b表示有从a开始的连续b个人退房(无输出)

了解过线段树的一眼就能看出来这又是一个区间查询问题,可以用线段树辅助解决,但是与RMQ 的线段树不同,这个也相对较难一些。

本体的解题思路分一下步骤:

  1. 建树(不再详细介绍)
  2. 查询
  3. 更新 

可分为以上四个步骤解题

先定义三个变量,(lsum)左连续表示从最左边开始的最长连续可用房间数,(rsum)右连续同上,(sum)连续表示该区间内最长的连续可用房间数

对于查询,我们可以这样操作,首先看一下整个大区间的最大连续长度是否大于所需要的,如果小于,说明肯定无法完成操作,直接返回0,如果可以,将区间从中间分开

  1. 左半边区间的sum够不够
  2. 左边的rsum和右半边的lsum相加够不够(意思就是两个区间的中间共同连续部分够不够用)
  3. 右半边的sum够不够

ps:这样判断的顺序不能变,因为题目要求的是要输出  最左边  的可用区间

如果符合第一个条件就递归到左区间内进行查询(因为可能左连续不一定是最大,例如(0,1,1,1,0),最大连续为3,左连续为0)

如果符合第三个同上

如果符合第二个条件,就可以直接输出最左边的下标(因为除了这一部分,其余的都已经包含在左右两边了)

至于lsum和rsum的值,应该是左子树的lsum的值和右子树的rsum的值(ps:特判一下,如果lsum等于rsum分别等于区间的总长度的话,还应该对应的加上右子树的lsum和左子树的rsum)

而sum的值则是左子树的sum和右子树的sum以及中间共同连续部分(左子树rsum+右子树lsum)取最大值

更新区间值的时候和RMQ的线段树类似,只是在递归回来的时候,把lsum,rsum,sum的值的更新方式变成上述即可

为了减少复杂度,还应该采用懒标记,标记有三个内容

  1. 标记为0表示区间内无可用的房间
  2. 标记为1表示区间内房间全部可用
  3. 标记为-1表示无需操作 

建树的时候,将所有的标记全部设为-1,在进行查询操作时,一旦找到了最左边的连续可用区间,将从该点开始连续一定长度的区间变为不可用,及标记为0,在更新时,将给定的从某一点a开始的长度为b的一段区间变为可用的,及标记设为1

在更新和查询的过程中,看一下当前的标记是不是-1,如果不是,说明需要进行标记下传操作,并在下传后将该位置的标记重新置为-1

代码如下

#include<iostream>
#include<cmath>
using namespace std;
#define endl "\n"
struct p {
	int l, r, lsum, rsum, sum, mark;
	int getlen() {
		return r - l + 1;
	}
	void getsum() {
		lsum = rsum = sum = (mark != 0 ? getlen() : 0);
	}
}c[200200];
void build(int l, int r, int k) {//建树 
	c[k].l = l;
	c[k].r = r;
	c[k].mark = -1;
	c[k].getsum();

	if (l == r)return;
	int mid = (l + r) / 2;
	build(l, mid, k * 2);
	build(mid + 1, r, k * 2 + 1);
}
int query(int w, int k) {//查询 
	if (c[k].l == c[k].r&&w == 1)return c[k].l;
	if (c[k].mark != -1) {//标记下传
		c[k * 2].mark = c[k * 2 + 1].mark = c[k].mark;
		c[k * 2].getsum();
		c[k * 2 + 1].getsum();
		c[k].mark = -1;
	}
	if (c[k].sum >= w) {
		if (c[k * 2].sum >= w)return query(w, k * 2);
		if (c[k * 2].rsum + c[k * 2 + 1].lsum >= w)return c[k * 2].r - c[k * 2].rsum + 1;
		if (c[k * 2 + 1].sum >= w)return query(w, k * 2 + 1);
	}
	else return 0;
}
void update(int l, int r, int mk, int k) {//更新
	if (l <= c[k].l&&c[k].r <= r) {
		c[k].mark = mk;
		c[k].getsum();
		return;
	}
	if (l > c[k].r || r < c[k].l)return;
	if (c[k].mark != -1) {//标记下传
		c[k * 2].mark = c[k * 2 + 1].mark = c[k].mark;
		c[k * 2].getsum();
		c[k * 2 + 1].getsum();
		c[k].mark = -1;
	}
	int mid = (c[k].l + c[k].r) / 2;
	if (r <= mid)update(l, r, mk, k * 2);
	else if (mid < l)update(l, r, mk, k * 2 + 1);
	else {
		update(l, r, mk, k * 2);
		update(l, r, mk, k * 2 + 1);
	}
	c[k].rsum = c[k * 2 + 1].rsum;
	c[k].lsum = c[k * 2].lsum;
	if (c[k * 2].lsum == c[k * 2].getlen())c[k].lsum += c[k * 2 + 1].lsum;
	if (c[k * 2 + 1].rsum == c[k * 2 + 1].getlen())c[k].rsum += c[k * 2].rsum;
	c[k].sum = max(c[k * 2 + 1].sum, max(c[k * 2].sum, c[k * 2].rsum + c[k * 2 + 1].lsum));
}
int n, m;
int op, a, b;
int main()
{
#ifdef endl
	cin.tie(0);
	cout.tie(0);
	ios::sync_with_stdio(0);
#endif
	cin >> n >> m;
	build(1, n, 1);
	while (m--) {
		cin >> op;
		if (op == 1) {
			cin >> a;
			int res = query(a, 1);
			cout << res << endl;
			if (res) {
				update(res, res + a - 1, 0, 1);
			}
		}
		else if (op == 2) {
			cin >> a >> b;
			update(a, a + b - 1, 1, 1);
		}
	}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
4S店客户管理小程序-毕业设计,基于微信小程序+SSM+MySql开发,源码+数据库+论文答辩+毕业论文+视频演示 社会的发展和科学技术的进步,互联网技术越来越受欢迎。手机也逐渐受到广大人民群众的喜爱,也逐渐进入了每个用户的使用。手机具有便利性,速度快,效率高,成本低等优点。 因此,构建符合自己要求的操作系统是非常有意义的。 本文从管理员、用户的功能要求出发,4S店客户管理系统中的功能模块主要是实现管理员服务端;首页、个人中心、用户管理、门店管理、车展管理、汽车品牌管理、新闻头条管理、预约试驾管理、我的收藏管理、系统管理,用户客户端:首页、车展、新闻头条、我的。门店客户端:首页、车展、新闻头条、我的经过认真细致的研究,精心准备和规划,最后测试成功,系统可以正常使用。分析功能调整与4S店客户管理系统实现的实际需求相结合,讨论了微信开发者技术与后台结合java语言和MySQL数据库开发4S店客户管理系统的使用。 关键字:4S店客户管理系统小程序 微信开发者 Java技术 MySQL数据库 软件的功能: 1、开发实现4S店客户管理系统的整个系统程序; 2、管理员服务端;首页、个人中心、用户管理、门店管理、车展管理、汽车品牌管理、新闻头条管理、预约试驾管理、我的收藏管理、系统管理等。 3、用户客户端:首页、车展、新闻头条、我的 4、门店客户端:首页、车展、新闻头条、我的等相应操作; 5、基础数据管理:实现系统基本信息的添加、修改及删除等操作,并且根据需求进行交流信息的查看及回复相应操作。
现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本微信小程序医院挂号预约系统就是在这样的大环境下诞生,其可以帮助管理者在短时间内处理完毕庞大的数据信息,使用这种软件工具可以帮助管理人员提高事务处理效率,达到事半功倍的效果。此微信小程序医院挂号预约系统利用当下成熟完善的SSM框架,使用跨平台的可开发大型商业网站的Java语言,以及最受欢迎的RDBMS应用软件之一的MySQL数据库进行程序开发。微信小程序医院挂号预约系统有管理员,用户两个角色。管理员功能有个人中心,用户管理,医生信息管理,医院信息管理,科室信息管理,预约信息管理,预约取消管理,留言板,系统管理。微信小程序用户可以注册登录,查看医院信息,查看医生信息,查看公告资讯,在科室信息里面进行预约,也可以取消预约。微信小程序医院挂号预约系统的开发根据操作人员需要设计的界面简洁美观,在功能模块布局上跟同类型网站保持一致,程序在实现基本要求功能时,也为数据信息面临的安全问题提供了一些实用的解决方案。可以说该程序在帮助管理者高效率地处理工作事务的同时,也实现了数据信息的整体化,规范化与自动化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值