Interval Tree(区间树)
网上好多人把区间树当成线段树。。线段树就叫Segment Tree好吧。只有两篇
(现在三篇了)和wiki是真的(也都没有具体的代码)。建议直接看wiki:https://en.wikipedia.org/wiki/Interval_tree (pdf: 链接:https://share.weiyun.com/3WXYiU6b 密码:5c75zn)
https://blog.csdn.net/qiaojialin/article/details/78213061
https://www.cnblogs.com/jcli/p/4574824.html
但是这个东西,没人知道不是没有道理的,是真的,没用。
Interval Tree大概分为三种:Centered Interval Tree、Augmented Tree、Medial- or Length-oriented Tree。下面说的为Centered Interval Tree。
实现的功能
给定(n)个区间(线段)。对于询问给定的一个区间或点,可以在(O(log n+m))时间内求出与询问区间相交/包含询问点的所有区间((m)是答案区间的数量)。
构造:(O(nlog n));空间复杂度:(O(4n))。
构造
区间树(Centered Interval Tree)是一个二叉树(上面csdn那篇写错了)。
依据所有线段确定一个中间点(x_{center})。设每个区间的端点为(l,r)。对于(r<x_{center})的区间分到左子树中构造;(l>x_{center})的区间分到右子树中继续构造;剩下的就是包含(x_{center})的区间,分别按(l)从小到大、(r)从大到小排序后的两种序列存在当前节点中。
也就是每个节点包含五个信息(原文比较清楚)
- A center point((x_{center}))
- A pointer to another node containing all intervals completely to the left of the center point((lson))
- A pointer to another node containing all intervals completely to the right of the center point((rson))
- All intervals overlapping the center point sorted by their beginning point(以下记为(S_a))
- All intervals overlapping the center point sorted by their ending point(以下记为(S_b))
(x_{center})的选取要保证划分到左右子树中的区间数各不超过(n/2),所以可以取所有端点的中位数作(x_{center})(可以用nth_element
做到(O(n)))。
想一个(log)建树好像是有点麻烦...
查询包含点(p)的区间
从根节点开始,若(p<x_{center}),则查询当前节点及左子树;若(p>x_{center}),查询当前节点及右子树;否则(p=x_{center}),当前节点所有区间就是答案。
查询一个节点时,若(p<x_{center})则该节点所有区间的(r>p),所以只需枚举(S_a)(按左端点排好序)中的区间就可以找到包含(p)的所有区间。
所以复杂度(O(log n+m))。
查询与给定区间相交的所有区间
设询问区间为([q_l,q_r])。它与原有区间([l,r])相交有两种可能:(l)、(r)至少有一个点在([q_l,q_r])中;([l,r])完全包含([q_l,q_r])。
第一种情况,可以建一棵线段树(csdn那篇用的B+树,没有必要吧),将每个区间插入到(l,r)两个位置去,每个节点存(l)或(r)在该节点区间内的所有区间。查询时区间查([q_l,q_r])即可(注意去重,可以合并时归并方便去重,也可以打标记)。复杂度(O(nlog n),O(log n+m))。
第二种情况,建一个Interval Tree。用([q_l,q_r])中任意一点(p)求与(p)相交的所有区间,然后判断这些区间是否包含([q_l,q_r])。这些区间一定也是答案区间(有可能与情况一重复),所以复杂度仍是(O(log n+m))。
扩展到高维
对于(N)维“区间”的查询依旧可以用Interval Tree。
基本同查询与给定区间相交的所有区间。首先建一个(N)维Range Tree存所有“区间”,对于每次查询先找出存在某个点 在给定(N)维询问区间内 的所有区间,即第一种情况。
对于第二种情况,建(N)棵Interval Tree解决每一维,(N)维答案的交集就是最终答案。
那个(N)维Range Tree,我以为是什么神奇的东西,原来就是。。(N)维线段树(线段树套线段树套线段树...)。。所以复杂度是(O(log^{N}n+Nlog n+Nm))的。
那个(N)维Range Tree可能可以用K-D Tree写。
应用
挺...蠢局限的。
首先它的作用可以用离线+树状数组/二维线段树实现,可能用到的情况是:强制在线并卡(log^2n)算法。其次它复杂度与答案区间数有关,需要题目保证(m)不大,不能任意询问。
例题:2020-2021 ICPC Brazil Subregional Programming Contest. M. Machine Gun(1.2s来卡(log^2n)的强制在线还就一主席树题够蠢的)