珂朵莉树总结
常常用于维护颜色段。随机数据下表现优秀,但构造数据随便卡。一定要看是否保证了数据随机。
前置
STL之set
。年少不学STL,学珂朵莉树两行泪。
set
内部是红黑树,内部不会出现值相同的元素。可重集使用multiset
,用法基本与set
一致。
插入删除
以下简写set<type>::iterator
为iter
-
s.insert(x)
,插入值为x
的元素,返回pair<iter,bool>
类型,前一个是指向插入元素的指针,后一个是返回插入是否成功(set
中已有等值元素时插入失败)。 -
s.erase(x)
,删除值为x
的所有元素,返回删除的元素个数。 -
s.erase(iter p)
,删除迭代器为p
的元素,要求迭代器合法。 -
s.erase(iter l,iter r)
,删除迭代器在 的元素。 -
s.clear()
,清空s
。
迭代器
-
begin()/cbegin()
,指向首元素的迭代器。 -
end()/cend()
,指向尾端占位符的迭代器,注意此处没有元素。 -
rbegin()/crbegin()
,指向逆向的首元素,可以理解为最后一个元素。 -
rend()/crend()
,指向逆向的尾端占位符,对应正向首元素的前一个位置,注意此处没有元素。
以上带c
的迭代器为只读类型。
查找
-
s.count(x)
,返回键值为x
的元素个数。 -
s.find(x)
,返回值为x
的元素的迭代器,如果不存在则返回end()
。 -
s.lower_bound(x)
,返回s
中首个不小于x
的元素的迭代器,如果不存在则返回end()
。 ,但是如果用lower_bound(s.begin(),s.end(),x)
则 。 -
s.upper_bound(x)
,返回s
中首个大于x
的元素的迭代器,如果不存在则返回end()
。复杂度同上。 -
set
没有自带的nth_element
,于是只能手写平衡树或者权值线段树或者pb_ds
来 查询第 大。直接使用nth_element(s.begin(),s.end(),k)
是 的。 -
s.empty()
,返回容器是否为空;s.size()
,返回容器内元素个数。
正式开始
结点
这样定义珂朵莉树的结点:
struct node{
int l,r;
mutable ll v;
node(const int &_l,const int &_r=-1,const ll &_v=0): ````l(_l),r(_r),v(_v){}
bool operator<(const node &t) const{
return l<t.l;
}
};
我们使用set<node> odt
来表示一棵珂朵莉树。``
接下来是核心操作。
给出一段区间
-
先在
s
中lower_bound
找到包含 的区间。 -
如果
是一个区间的左端点,那么不管。 -
否则删除原来的结点,然后插入两个新结点。
返回分裂后右边区间的迭代器。
auto split(int x) {
auto it=odt.lower_bound(node(x,0,0));
if (it!=odt.end()&&it->l==x) return it;
--it;
int l=it->l,r=it->r,v=it->v;
odt.erase(it);
odt.insert(node(l,x-1,v));
return odt.insert(node(x,r,v)).first;
}
区间推平操作。防止段数过多导致复杂度退化成暴力。
将区间
void assign(int l,int r,int val){
iter itr=split(r+1),itl=split(l);
odt.erase(itl,itr);
odt.insert((node){l,r,val});
}
必须先split(r+1)
,再split(l)
,因为这样必然不会删掉以
将一段区间提取出来进行操作,与
复杂度
之后立即
数据随机下,是均摊
之后不调用
只有在随机数据下正确。set
实现的复杂度为list
实现是
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效