首页 > 其他分享 >区间合并

区间合并

时间:2023-11-06 19:46:38浏览次数:28  
标签:交集 ed 合并 st item 区间 维护

AcWing笔记 -- 区间合并


前言

给定多个区间,如[1, 8] , [7 , 12] , [15, 18], [18 , 25]。可以看出,这些区间之间是有交集的,比如[1,8]和[7,12]以及[15,18],[18,25]。这两对区间可以合并,变为[1, 12]以及[15 , 25]。区间合并解决的就是给定多个区间段,让我们判断哪些区间可以合并,最后给出独立区间段个数的问题。

实现

对于给定两两区间A,B之间,显然有三种情况。

1. B区间包含于A区间。
2. B区间与A区间有交集但不含于A区间。
3. B区间与A区间无交集。

三种情况的示意图如下
image

显然前两种情况是需要合并的,而第三种情况下,说明A区间与后面的区间不会再有交集了。因此A区间已经成为一个独立区间。
注意由于我们是从大到小依此扫描,不会出现B区间的头大于A区间的头的情况

我们以下面这道题为例,实现区间合并

给定 n个区间 [li,ri],要求合并所有有交集的区间。

注意如果在端点处相交,也算有交集。

输出合并完成后的区间个数。

例如:[1,3]和 [2,6] 可以合并为一个区间 [1,6]。

输入格式

第一行包含整数 n。

接下来 n 行,每行包含两个整数 l和 r。

输出格式

共一行,包含一个整数,表示合并区间完成后的区间个数。

数据范围

1≤n≤100000,
−109≤li≤ri≤109

题解如下:

对于给出的每个区间,我们用pair型的vector来读入存储。而且存储之后排一下序。
sort对pair排序,会先以其first作为基准排序,再以其seconed作为基准排序。

排序之后我们便开始区间合并。合并操作都在merge函数中。
定义一个st以及ed,分别指向我们当前所维护的区间的头尾。为防止与输入冲突,初始化为负无穷。
然后去扫瞄读入的排好序的每个区间,并与维护区间进行上述三种情况的判断。

  1. 若维护区间与当前区间无交集,代表着当前区间的头大于维护区间的尾,也就是item.second > ed ,说明维护区间与后续区间再无交集,因此当前的维护区间已经成为一个独立区间,将其加入到答案数组中。同时更新当前维护区间为此时的item,即令st = item.first , ed = item.second。当然这里要特殊考虑第一次的情况,第一次更新时只更新维护区间而不将维护区间加入答案。
  1. 若维护区间与当前区间有交集(若1不成立即判断为有交集),进行的为上述情况1,2。更新当前维护区间的尾,即让ed = max(ed,item.second),这样包含了两种情况的更新
  1. 注意所有区间遍历完之后,一定会剩下一个维护区间为加入答案数组之中,所以循环退出之后要加上最后的维护区间。

最后代码如下

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
typedef pair<int, int> PII;
vector<PII> ran;
void merge(vector<PII>& range)
{
	vector<PII> ans;//答案
	int st = -0x3f3f3f3f;
	int ed = st;
	//st以及ed为当前维护区间的区间头尾
	//对于每个item,都为下一个将要判断的区间
	for (auto item : range)//c++区间遍历
	{
		if (ed < item.first)//若没有交集,说明当前维护的区间与以后的区间再无并集,找到独立区间
		{
			if(ed!=-0x3f3f3f3f)//第一次的特殊情况。
			ans.push_back({ st, ed });
			st = item.first;
			ed = item.second;//更新当前所要维护的区间
		}
		else//若有交集,合并
		{
			ed = max(ed, item.second);//考虑了item在所维护区间内部以及item与所维护区间有一部分交集两种情况
		}
	}
	//显然对于最后一个item,可能是独立的区间,也可能合并后进入维护区间,不论如何,在最后一次循环后总是会留下一个维护区间未加入答案中,这里加上
	if(st!=-0x3f3f3f3f)ans.push_back({ st,ed });//if语句防止无输入的range
	range = ans;
}	
int main()
{
	int n;
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		int l, r;
		cin >> l >> r;
		ran.push_back({ l,r });
	}
	sort(ran.begin(), ran.end());
	merge(ran);
	cout << ran.size() << endl;
	return 0;
}

标签:交集,ed,合并,st,item,区间,维护
From: https://www.cnblogs.com/CrescentWind/p/17813533.html

相关文章

  • [NOI2016] 区间
    [NOI2016]区间题目描述在数轴上有$n$个闭区间从$1$至$n$编号,第$i$个闭区间为$[l_i,r_i]$。现在要从中选出$m$个区间,使得这$m$个区间共同包含至少一个位置。换句话说,就是使得存在一个$x$,使得对于每一个被选中的区间$[l_i,r_i]$,都有$l_i\leqx\leqr_i$。对......
  • 将两个列表合并成一个字典 dict(zip())方法
    假设你有如下两个list:keys=['name','age','food']values=['Monty',42,'spam']如何转变成:a_dict={'name':'Monty','age':42,'food':'spam'}解决方法:d......
  • Endnote 教程之合并 endnote library
    1.简单合并两个library (1)Library1:File--SaveaCopy--可以把一个library保存为enl格式  (2)打开Library2,点击Import按钮,选择Library1的enl文件即可   2.合并其他数据库某一部分文献(1)Library1:选择一部分文献,点击File--CompressedLibrary (2)解压导出......
  • 区间分组贪心
    是我见识少了,真没见过这种的……传送门如果看成有序排列的\((x,y)\)配对,那么可以写成\(r_x-l_y\)。(因为如果是负数,会在\(y,x\)的时候被枚举到,这样就不用考虑max和绝对值了)。于是,就是分成恰好长度为\(\frac{n}{2}\)的两组,一组贡献为\(r_i\),一组贡献为\(l_i\),求贡献最大值。假设......
  • cf1709E. XOR Tree(启发式合并入门)
    cf1709E.XORTree贪心是显然的,关键是如何合并两棵子树的信息,可以采用启发式合并。#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>#include<map>#include<vector>#include<set>#include<ctime>#include<unordered_ma......
  • cf1834E. MEX of LCM(维护右端点计算区间lcm)
    cf1834E首先可以估计一下答案的量级,因为小于答案的质数都要必须要出现,5e6以内的质数大概就是3e5,所以答案不超过5e6。我们维护以i右端点的lcm的值,这些值的数量不会太多,因为每次增长都至少×2,所以是log级别。每次新加的时候记得更新和去重即可。#include<cstdio>#include<algor......
  • 区间DP入门
    石子合并别人讲过太多了,蒟蒻就不说了。Polygon这题跟石子合并类似,只是多输出了个先清除哪条边可以使得值最大。因为我们不确定先删那一条,我们就再复制一遍添到输入的结尾,就变成了$2\timesN-1$。我们思考最大值是由哪些贡献的。最大值与最大值运算。最小值乘上最小值......
  • 文件合并小工具
    可以搜索工具所在目录下的所有指定扩展名文件,并将文件合并成一个大文件,同时生成索引头文件   首次使用会自动生成配置文件.配置说明如下:扫描扩展名=.bin.FON<<<<<<<<<<<<<<<<<要合并的文件的扩展名固件输出路径=\merage.fm<<<<<<<<<<<<<<<<&l......
  • 字节笔试题-区间异或
    题目给两个长度为n的数组a,b,请你计算出有多少个区间[l,r],满足\(a_{l}\oplusa_{l+1}\oplusa_{l+2}\oplus\ldots\oplusa_{r}=b_{l}\oplusb_{l+2}\oplusb_{l+2}\oplus\ldots\oplusb_{r}\)(\(\oplus\)表示按位异或)输入描述第一行输入一个整数n,表示数组长度。第二行输......
  • Java面试题:链表-合并两个排序的链表
    描述输入两个递增的链表,单个链表的长度为n,合并这两个链表并使新链表中的节点仍然是递增排序的。示例输入:{1,3,5},{2,4,6}返回值:{1,2,3,4,5,6}原题地址:https://www.nowcoder.com/practice/d8b6b4358f774294a89de2a6ac4d9337代码实现packagecom.example.demo.linked;......