区间树(Interval Tree)
参考资料
实现的功能
给定个区间(线段),对于给定的查询区间或点,可以在时间内求出与查询区间相交/包含查询点的所有区间(是答案区间的数量)。
构造
区间树是一个二叉树。依据所有区间确定一个中间点,设每个区间的左右端点分别为和。对于的区间分到左子树中构造;的区间分到右子树中继续构造;剩下的就是包含的区间,分别按升序、降序的两种序列存在当前节点中。也就是每个节点包含五个信息:
- 中心点
- 指向另一个节点的指针 ,该节点包含完全位于左侧的所有区间
- 指向另一个节点的指针 ,该节点包含完全位于右侧的所有区间
- 所有包含的区间按照左端点排序(记为)
- 所有包含的区间按照右端点排序(记为)
的选取要使得划分到左右子树中的区间数相近。对所有区间的左右端点排序后,取中位数作为通常可以满足要求。
(逻辑:左子树的区间的两个端点都在左侧,右子树的区间的两个端点都在右侧。排序后的中位数将左右端点划分为两部分,两侧端点数量接近相等。)
取所有区间的端点时间复杂度为,对所有端点排序的时间复杂度为。因此构建区间树的时间复杂度为,空间复杂度为。
查询包含点的区间(stabbing query)
从根节点开始,若,则查询当前节点以及左子树;若,查询当前节点以及右子树;若,当前节点所有的区间就是答案。
查询节点包含的区间,只需要找到满足的区间。
若,则节点所有区间都满足,所以只需要找满足的区间即可,从(区间按照左端点排好序)中枚举即可。
若,则节点所有区间都满足,所以只需要找满足的区间即可,从(区间按照右端点排好序)中枚举即可。
区间树查询包含查询点的时间复杂度为,具体分析如下:
-
树的搜索过程
区间树是一棵平衡二叉树,其高度为。搜索时,从根节点开始,按照查询点与区间中心点的关系递归向下,最多访问节点数量为树的高度,即个节点。
-
结果处理
访问每个节点时,处理与查询点相关的区间,总计个。
因此,时间复杂度为两部分的加和。
查询与给定区间相交的所有区间
要使结果区间与查询区间相交,必须满足以下条件之一:
- 的起点或终点位于内
- 完全包围
首先找满足第一个条件的区间,即起点和/或终点位于内的所有区间。
我们可以使用区间集合内所有的起点和终点构建一棵二叉搜索树,二叉搜索树的每个节点都有一个指向其对应区间(起点或终点等于该节点值)的指针。在时间内搜索节点值在的节点,将这些节点指向的区间添加到结果列表中。(有个疑问,这里的时间复杂度不是吗?例如当完全覆盖所有区间时,需要遍历搜索树中的所有节点。)
起点和终点都在内的区间可能被重复添加,因此可以通过在每个区间上使用二进制标志来标记它是否已经被添加到结果列表中。
接着找满足第二个条件的区间,有个技巧:在内选择任意一点并利用Interval Tree查找与该点相交的所有区间,找到的区间一定包含所有完全包含的区间。找到的区间可能与条件一重复,注意删除重复项。查找满足第二个条件的区间的复杂度为。
综合条件一和条件二,查询与给定区间相交的所有区间的时间复杂度仍为。