struct node
{
int l , r ; mutable int v ;
friend bool operator < ( node x , node y ) {
return x.l < y.l ;
}
};
m
u
t
a
b
l
e
mutable
mutable 意为 “可变的”,方便我们在遍历迭代器时可以直接 it->v+=
进行修改
set<node> s ;
auto split( int x ) // 分裂 x-1 与 x 所在段,并返回 x 所在段的迭代器,方便接下来遍历
{
auto it = s.lower_bound((node){x,0,0}) ;
if( it != s.end() && it->l == x ) { // x 恰为左端点,不用分裂了
return it ;
}
it -- ;
if( it->r < x ) return s.end() ; // 没有任何区间包含 x (x=n+1) ,后续不用遍历了
int l = it->l , r = it->r , v = it->v ;
s.erase(it) ;
s.insert((node){l,x-1,v}) ;
return s.insert((node){x,r,v}).first ;// 小技巧,直接 .first 返回插入段的迭代器
}
上面 三种情况的讨论一种也不能少!!否则 RE 套餐送上
void assign( int l , int r , int x )
{
auto itr = split(r+1) , itl = split(l) ;//顺序不能换
s.erase( itl , itr ) ;
s.insert((node){l,r,x}) ;
}
注意这里需要先 s p l i t ( r + 1 ) split (r+1) split(r+1) 后 s p l i t ( l ) split (l) split(l) ,这是因为如果反过来, i t l itl itl 会先指向 [ l , > r ] [l,>r] [l,>r] 区间,然后 s p l i t ( r + 1 ) split(r+1) split(r+1) 就把它给删掉了!!
迭代器被删除出 S T L STL STL 容器后,其指代的值仍能访问到 (指针访问) ,但不能再进行任何与 原 S T L STL STL 有关的操作!!
int query( int l , int r , int x )
{
auto itr = split(r+1) , itl = split(l) ;
int res = 0 ;
for( ; itl != itr ; itl ++ ) {
if( itl->v == x ) res += (itl->r)-(itl->l)+1 ;
}
return res ;
}
int bt[27] ;
void Sort( int l , int r )
{
auto itr = split(r+1) , itl = split(l) ;
for(auto it = itl ; it != itr ; it ++ ) {
bt[it->v] += (it->r)-(it->l)+1 ;
}
s.erase( itl , itr ) ;// 先记录信息,后删
int now = l ;
for(int i = 0 ; i < 26 ; i ++ ) {
if( !bt[i] ) continue ;
s.insert((node){now,now+bt[i]-1,i}) ;
now += bt[i] ;
bt[i] = 0 ;
}
}
(一些拓展操作
总结一下:
珂朵莉树 适合维护 带有区间推平 (assign) 操作的问题
为什么说它是一个暴力数据结构,观察 q u e r y 、 a d d query、add query、add 等操作本质是 暴力枚举 s e t set set 中连续段,复杂度严重依赖颜色段数
经过一些严谨的证明,可以得到:在 a s s i g n 、 q u e r y assign、query assign、query 等操作完全随机生成的情况下, s e t set set 中颜色段数总是 O ( l o g n ) O(logn) O(logn) 的
正因为是暴力,所以能做的操作十分多 甚至频频吊打正解
这使得我们能跨级实现一些令人匪夷所思的 题(骗分
随机数据下十分强力 例
然而,只用珂朵莉树来维护 a s s i g n assign assign 操作时,复杂度是严格 O ( n l o g n ) O(nlogn) O(nlogn) 的
Proof :
考虑一次推平操作时,被删除的段分两种:
完全被包含的,删掉就没了,而总段数是 O ( n ) O(n) O(n) 的
与该段相交的,由于这样的区间最多只有两个,每次推平最多删两段
所以均摊复杂度正确,不依赖于数据随机生成
基于这一点,我们常会用这种 颜色段均摊 的思想维护连续段,再用其它数据结构维护查询操作,以实现正解的复杂度