这道题给的一个条件十分奇怪:区间(a,b)能转移到区间(c,d)当且仅当 c<a<d c < a < d or c<b<d c < b < d ,想一下有两种情况符合这个定义
- (a,b)与(c,d)互相不包含且有交集
- (a,b) ⊂ ⊂ (c,d)
这两种情况又有区别:第一种情况下(a,b)和(c,d)互相联通,而第二种情况只能(a,b)–>(c,d). 如果说第一种情况可以用并查集维护的话,第二种情况就十分难处理
另外题目有一个特殊的限制:区间是按照长度从小到大严格递增给出的,这个条件不知道该怎么用
从简单想起
如果只考虑两种情况中的第一种情况,显然可以想到并查集
注意到这样一种关系是可以传递的,所以(a,b)和(c,d)联通后,这个区间相当于变成了一个长区间(min{a,b},max{c,d}),所以我们对并查集的每个节点再维护一个l,r表示最远延伸的左右端点
对于当前区间(ai,bi),如何知道他与哪些区间有相交的部分呢?可以想到线段树,对于之前的每个独立的区间(即并查集中的一棵棵树)在线段树的对应区间上打一个标记,然后查询时将ai和bi分别带入线段树,从根查询到叶子的这条路径上,如果某个节点有标记,说明这个区间包含了ai/bi,则(ai,bi)与原区间有交错
这样处理忽略了一种情况,当(ai,bi) ⊂ ⊂ 原某区间时,也会被误查找到,但注意到题目的条件:区间按照长度递增给出,说明之前的区间中不可能有包含当前区间的区间,于是这个问题就解决了
尝试分析这个问题的复杂度,首先这个标记是不会下放的,每个区间打的标记数是logn级别,所以标记的总数是nlogn级别的
再考虑每个标记会被访问多少次,由于一个标记被访问一定会同时进行一个union的操作,所以访问一次之后这个标记就没有价值了,因为之后我们一定会用它的祖先标记。所以每个标记最多被访问一次。这样复杂度有了保证
‘于是这里有一个细节:每次处理完标记以后一定要将标记数组清空,否则复杂度会炸
第一段中的第二种情况还没有考虑,我们尝试分析这样的情况有什么性质
我们设第一种情况的区间移动为A移动,第二种为B移动,那么一个区间到另一个区间的route会是个由A,B构成的字符串
其中全A的部分相当于在并查集中的一棵树中游走
然后我们发现了一个重要的性质:假设有一个集合S,里面的元素是并查集中祖先相同的区间,左右最远端点为l,r;假设存在一个 a∉S a ∉ S 且a包含S中的某一个元素,那么a一定包含(l,r)
这个结论很好证明,考虑反证法:如果 a∉