尾递归做区间合并插入示例

有一区间列表ranges [[0, 2], [4, 6], [8, 10], [12, 14]],按序排列好了的,没有交集。现在有一新范围range_new [4, 9],进行合并。

采用递归思想,可以用range_new依次和ranges中的范围比较

如果range_new是子集,直接返回

如果range_new小于当前范围,左边直接插入

如果range_new大于当前范围,递归ranges右边的范围比较

如果range_new存在交集,求并集,删除当前范围,如果最大值变化,用并集递归ranges右边的范围比较;如果最大值没有变化,直接替换到当前范围位置

求并集代码,返回状态码, -1是左边插入, 1表示继续递归遍历右边,2表示需要更新当前范围,并与后面的范围进行比较,0表示仅替换当前范围

# 求并集def xor(range_old, range_new):    # 【插入左边】新范围最大值小于老范围最小值    if range_new[1] < range_old[0]:        return -1, range_new    # 【插入右边】新的最小值大于老范围的最大值,在右边    elif range_new[0] > range_old[1]:        return 1, range_new    # 存在交集    else:        # 最小值更新        if range_new[0] < range_old[0]:            # 【最小值更新】不用遍历列表            if range_new[1] < range_old[1]:                return 0, [range_new[0], range_old[1]]            # 【最小值最大值更新】,需要判断最大值与后面的范围是否有交集            else:                return 2, range_new        # 最小值不用更新        else:            # 【不更新】最大值也不用更新            if range_new[1] <= range_old[1]:                return 0, None            # 【最大值更新】,需要判断最大值与后面的范围是否有交集            else:                return 2, [range_old[0], range_new[1]]
 
# 尾递归def tail_rescuvie(ranges, range_new, start=0):    print(‘Start:‘, range_new)    # ranges末尾插入    if start >= len(ranges):        ranges.append(range_new)        return

result, range_or = xor(ranges[start], range_new)    # 左边插入    if result == -1:        ranges.insert(start, range_new)    # 继续遍历右边    elif result == 1:        tail_rescuvie(ranges, range_new, start+1)    # 替换    elif result == 0:        if range_or is not None:            ranges[start] = range_or        return    # 删除范围,用新范围继续向后递归    elif result == 2:        del ranges[start]        print(‘Rescuvie:‘, start, range_new, range_or)        return tail_rescuvie(ranges, range_or, start)    else:        pass

if __name__ == ‘__main__‘:    # ranges = [] # [[1, 2], [8, 9], [100, 200], [205, 300]]    import time    ranges = [[x, x+2] for x in range(0, 15, 4)]    print ‘ranges:‘, ranges    start = time.time()    tail_rescuvie(ranges, [4, 9])    print ‘ranges:‘, ranges

print ‘cost:‘, time.time() – start
执行结果如下:

ranges: [[0, 2], [4, 6], [8, 10], [12, 14]]
(‘Start:‘, [4, 9])     与[0,2]比较
(‘Start:‘, [4, 9])     与[4,6]比较合并
(‘Rescuvie:‘, 1, [4, 9], [4, 9])
(‘Start:‘, [4, 9])   与[8,10]比较合并
ranges: [[0, 2], [4, 10], [12, 14]]
cost: 0.00200009346008

时间: 2024-10-22 17:30:00

尾递归做区间合并插入示例的相关文章

(树链剖分+区间合并)HYSBZ - 2243 染色

题意: 两个操作: 1.把一条树链上的所有点权值变为w. 2.查询一条树链上有多少个颜色段 分析: 一看就是区间合并,做这到题首先需要一定的区间合并基础, 不过这题合并这部分在线段树区间合并中已经算是非常的简单的了. 线段树部分没有难度. 那么难点在于,在往LCA上走的时候,我们如何进行区间合并. 本来我想着, 在向上走的时候顺便进行区间判断并且合并,但是似乎有问题. 其实,可以将两步分开,先算出区间没合并之前的颜色段数,再次进行Top,判断颜色是否相等,相等就减掉. 代码: 1 #includ

HDU 2871 Memory Control(线段树&#183;区间合并&#183;Vector)

题意  模拟内存申请  有n个内存单元  有以下4种操作 Reset  将n个内存单元全部清空 New x  申请一个长度为x的连续内存块  申请成功就输出左端 Free x  将x所在的内存块空间释放  释放成功输出释放的内存始末位置 Get x  输出第x个内存块的起始位置 Reset 和 New 都是基本的区间合并知识  比较简单  Free和Get需要知道内层块的位置  所以我们在New的时候要将申请的内存块的始末位置都存起来  两个内层块不会相交  这样就能通过二分找到需要的内层块了

HDU 1540 &amp;&amp; POJ 2892 Tunnel Warfare (线段树,区间合并).

~~~~ 第一次遇到线段树合并的题,又被律爷教做人.TAT. ~~~~ 线段树的题意都很好理解吧.. 题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1540 http://poj.org/problem?id=2892 ~~~~ 我的代码:200ms #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #defin

【bzoj4811】[Ynoi2017]由乃的OJ 树链剖分+线段树区间合并

题目描述 由乃正在做她的OJ.现在她在处理OJ上的用户排名问题.OJ上注册了n个用户,编号为1-",一开始他们按照编号 排名.由乃会按照心情对这些用户做以下四种操作,修改用户的排名和编号:然而由乃心情非常不好,因为Deus天 天问她题...因为Deus天天问由乃OI题,所以由乃去学习了一下OI,由于由乃智商挺高,所以OI学的特别熟练她 在RBOI2016中以第一名的成绩进入省队,参加了NOI2016获得了金牌保送 Deus:这个题怎么做呀? yuno:这个不是NOI2014的水题吗... Deu

hdu5316 Magician(线段树区间合并)

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5316 题意:有n个精灵,每个精灵有一个能力值,有两种操作①改变某一个精灵的能力值②查询区间[L,R]里面位置奇偶相间的能力值的最大和. 分析:这题线段树区间合并可以做.每个节点保存4个信息:①以奇位置开始偶位置结束的奇偶序列最大和②以奇位置开始奇位置结束的奇偶序列最大和③以偶位置开始偶位置结束的奇偶序列最大和④以偶位置开始奇位置结束的奇偶序列最大和 合并的时候,以奇位置开始偶位置结束的奇偶序列最大和=m

HDU 3911 区间合并求最大长度的问题

http://vjudge.net/problem/viewProblem.action?id=21557 题目大意: 每进行一次颜色改变都可以把一段区间内的黑石头变成白石头,白石头变成黑石头,最后问区间内黑石头连续的最大长度 这里我们可以用rev[]作为lazy标记,每次进行改变,rev[]^1 因为有黑白两种石头,我们求连续区间,需要维护黑,白两种石头的左侧最多,右侧最多和全部最多,所以我们这里可以用一个二维数组进行描述 每次做出改变,只要将黑白石头的值进行交换即可就方便了很多 对于最后访问

POJ 3667 Hotel ( 线段树区间合并 )

题目链接~~> 做题感悟:这题是接触线段树区间合并的第一题,做的很纠结. 解题思路: 注意线段树上节点代表的信息 : 每个节点需要维护 lc , rc , mc ,add ,见下图: add 为懒惰标记.假设 i 代表父亲节点编号,左儿子为  i * 2  ,右儿子为 i * 2  + 1 ,那么我们可以得到 : T [ i ] .lc 首先加上左儿子的左边的空格数,然后需要判断一下,如果左儿子的左节点占满了整个左区间时需要再加上右儿子的左边的空格数.同理 T [ i ] .rc 也可以这样得到

HDU 3308 LCIS (端点更新+区间合并)

刚刚做了两道LCIS,碰到这道线段树,脑抽了似的写 线段树+dp(LCIS),贡献一发TLE. 才想到要区间合并,query函数写了好久.下面有详细注释,参见代码吧~~欢迎点赞,欢迎卖萌~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3308 #include<cstdio> #inc

算法学习——区间合并

区间合并就是将坐标轴中两个存在交集的区间合并成一个区间. 代码: #include<bits/stdc++.h> using namespace std; const int N = 1000010; typedef pair<int,int> PII; //用来存放区间的左右端点 vector<PII>seg; int n,l,r; //合并区间操作函数 int merge(){ //存放合并完成后的区间的数组 vector<PII>res; //初始化区