珂朵莉树总结

常常用于维护颜色段。随机数据下表现优秀,但构造数据随便卡。一定要看是否保证了数据随机

前置

STL之set。年少不学STL,学珂朵莉树两行泪。

set内部是红黑树,内部不会出现值相同的元素。可重集使用multiset,用法基本与set一致。

插入删除

以下简写set<type>::iteratoriter

  • s.insert(x),插入值为x的元素,返回pair<iter,bool>类型,前一个是指向插入元素的指针,后一个是返回插入是否成功(set中已有等值元素时插入失败)。

  • s.erase(x),删除值为x所有元素,返回删除的元素个数。

  • s.erase(iter p),删除迭代器为p的元素,要求迭代器合法。

  • s.erase(iter l,iter r),删除迭代器在[l,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()O(logn),但是如果用lower_bound(s.begin(),s.end(),x)O(n)

  • s.upper_bound(x),返回s中首个大于x的元素的迭代器,如果不存在则返回end()。复杂度同上。

  • set没有自带的nth_element,于是只能手写平衡树或者权值线段树或者pb_dsO(logn)查询第k大。直接使用nth_element(s.begin(),s.end(),k)O(n)的。

  • 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来表示一棵珂朵莉树。``

接下来是核心操作。

split

给出一段区间[l,r]pos,要将其分割成[l,pos1],[pos,r]

  • 先在slower_bound找到包含pos的区间。

  • 如果pos是一个区间的左端点,那么不管。

  • 否则删除原来的结点,然后插入两个新结点。

返回分裂后右边区间的迭代器。


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;
}

assign

区间推平操作。防止段数过多导致复杂度退化成暴力。

将区间[l,r]全部推平。就是先把l,r的迭代器分裂出来,然后把这个区间内的迭代器全部删除,再插入一个。

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),因为这样必然不会删掉以l作为左区间的元素。而先分裂左端点,在分裂右端点时,可能因为左右端点在同一个段里面导致元素被删除而迭代器失效。

perform

将一段区间提取出来进行操作,与assign类似。只是将删除改为遍历。

复杂度

perform之后立即assign

数据随机下,是均摊O(mlogn),其中m是操作次数,n为结点个数,可以认为nm

perform之后不调用assign

只有在随机数据下正确。set实现的复杂度为O(nloglogn)list实现是O(nlogn)

posted @   RandomShuffle  阅读(2)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示