珂朵莉树是一种比较暴力的数据结构,一般需要数据随机,且有区间推平操作。
前置知识
set(STL,应该都懂吧)
算法用途
维护数组,支持区间推平加其他操作。
算法复杂度
时间
O ( n log 2 n ) O(n\log ^2n) O(nlog2n)
空间
O ( n ) O(n) O(n)
算法实现
储存
因为数据随机,且有区间推平操作,所以在大部分情况下,珂朵莉树维护的数组会有相邻且相等的一段数。
我们尝试用另一种方法去记录这些数。
我们定义一个 struct,里面包含 l , r , v l, r, v l,r,v,分别表示区间左端点、右端点和区间内数的值。然后把每一段相邻且相等的数记录成一个区间,并把维护的数组中所有区间按照左端点排序放在一个 set 里面。
比如说, [ 1 , 1 , 1 , 3 , 5 , 5 , 2 , 2 ] [1,1,1,3,5,5,2,2] [1,1,1,3,5,5,2,2],就可以储存成 [ { 1 , 3 , 1 } , { 4 , 4 , 3 } , { 5 , 6 , 5 } , { 7 , 8 , 2 } ] [\{1,3,1\},\{4,4,3\},\{5,6,5\},\{7,8,2\}] [{1,3,1},{4,4,3},{5,6,5},{7,8,2}]
推平
推平操作是珂朵莉树的重点,推平操作将区间 [ l , r ] [l, r] [l,r] 里的数设成同一个值 k k k。
那么在珂朵莉树中,我们只需要找出 l , r l, r l,r 所在的区间(第 i i i 个和第 j j j 个),然后将他们分别分裂成 { l i , l − 1 } , { l , r i } \{l_i,l - 1\},\{l,r_i\} {li,l−1},{l,ri} 和 { l j , r } , { r + 1 , r j } \{l_j,r\},\{r+1,r_j\} {lj,r},{r+1,rj}。最后将 l , r l,r l,r 所包括的区间全部删除,并插入一个 { l , r , k } \{l, r, k\} {l,r,k} 。
或者 l , r l, r l,r 在同一个区间中,那么我们把这段区间分成 { l i , l − 1 } , { l , r } , { r + 1 , r i } \{l_i,l-1\},\{l,r\},\{r+1,r_i\} {li,l−1},{l,r},{r+1,ri},然后更改 { l , r } \{l, r\} {l,r} 区间即可。
其他操作
和推平操作一样,我们先把区间分裂了,然后枚举每一个被 l , r l, r l,r 包含的区间,更改或者查询他们的值。