珂朵莉树,又叫老司机树($Old\, Driver \, Tree$)

是一种暴力出奇迹,就怕数据不随机的数据结构。

适用

需要用线段树维护一些区间修改的信息……

像是区间赋值(主要),区间加……

原理

暴力还需要原理吗……

首先通过维护区间及其中的值,使操作次数趋于$\log N$

其次通过图省事高效的红黑树 set 维护区间保证$\log N$的复杂度。

但是如果出题人毒瘤不讲情理卡珂朵莉树的话那也没办法。

最劣复杂度单次修改$\Theta(N)$

区间太好看辣(雾

首先有区间$[1,Inf]$

突然我们想修改一段的值$[A,B]$为$1$

于是先把$[1,Inf]$切开,用三个不同的区间代替原区间。

那好了。

我们又后悔了,要把从$[C,D](C<A \ and \ B<D)$再赋$1$

好多区间,怎么办?暴力

先切片。

然后把过期的区间全部删掉!

最后补上一个修好的区间

实现

这里我们用 雅礼Day5-联 来稍讲

<内网链接>

首先要定义节点(就是区间)

struct Seg{
#define IT set<Seg> ::iterator
LL l,r;
mutable int v;
Seg(LL l,LL r,int v){
this->l=l;
this->r=r;
this->v=v;
}
friend bool operator < (const Seg &a,const Seg &b){
return a.l<b.l;
}
};

里面有一点点内容。

mutable 是 ’可变的‘ 关键字,在后面我们要在 set 上直接修值时必须把这个声明为可变

下面重载$<$是为了把$Seg$塞进 set 里

一定要重定义一个$iterator$以后写函数要用。

然后是核心函数:$split$(切片)

IT split(LL pos){
IT p=q.lower_bound(Seg(pos,0,-1));
if(p!=q.end()&&p->l==pos)return p;
p--;
LL l=p->l,
r=p->r;
int v=p->v;
q.erase(p);
q.insert(Seg(l,pos-1,v));
return q.insert(Seg(pos,r,v)).first;
}

这个函数的意义就是把$pos$所在的区间切开并返回后面一个区间的迭代器。

剩下所有的函数都以$split$为基础

区间修改:

void change(LL l,LL r,int v){
IT rid=split(r+1),lid=split(l);
q.erase(lid,rid);
q.insert(Seg(l,r,v));
}

区间异或$1$:

void filp(LL l,LL r){
IT rid=split(r+1),lid=split(l);
for(;lid!=rid;++lid) lid->v^=1;//在这里改
}

如果想区间加或减就直接拿这个改

注意!一定要先切$r+1$再切$l$,不然,如果$l,r$位于一个区间,就会使$lid$维护的信息被$r+1$切开导致无效。

好像就没啥了,

现在是这个题的源码:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <set>
#define N 111111
#define LL long long
using namespace std; struct Seg{
#define IT set<Seg> ::iterator
LL l,r;
mutable int v;
Seg(LL l,LL r,int v){
this->l=l;
this->r=r;
this->v=v;
}
friend bool operator < (const Seg &a,const Seg &b){
return a.l<b.l;
}
};
set <Seg> q;
int qn; IT split(LL pos){
IT p=q.lower_bound(Seg(pos,0,-1));
if(p!=q.end()&&p->l==pos)return p;
p--;
LL l=p->l,
r=p->r;
int v=p->v;
q.erase(p);
q.insert(Seg(l,pos-1,v));
return q.insert(Seg(pos,r,v)).first;
}
void change(LL l,LL r,int v){
IT rid=split(r+1),lid=split(l);
//cout<<l<<" "<<r<<endl;
//cout<<lid->l<<" "<<rid->l<<endl;
q.erase(lid,rid);//puts("1");
q.insert(Seg(l,r,v));
}
void filp(LL l,LL r){
IT rid=split(r+1),lid=split(l);
for(;lid!=rid;++lid) lid->v^=1;
}
LL query(){
for(IT i=q.begin();i!=q.end();i++){
if(i->v==0){
return i->l;
}
}
return (*--q.end()).r+1;
}
int main(){
const LL MAXN=100000000000000001;
LL l,r;
int opt;
scanf("%d",&qn);
q.insert(Seg(1,MAXN,0));
for(int i=1;i<=qn;i++){
scanf("%d%lld%lld",&opt,&l,&r);
if(l>r)continue;
switch(opt){
case 1://puts("61");
change(l,r,1);//puts("10");
break;
case 2:
change(l,r,0);
break;
case 3:
filp(l,r);
break;
}//puts("21");
printf("%lld\n",query());
}
}

珂朵莉树(ODT)笔记的更多相关文章

  1. 「学习笔记」珂朵莉树 ODT

    珂朵莉树,也叫ODT(Old Driver Tree 老司机树) 从前有一天,珂朵莉出现了... 然后有一天,珂朵莉树出现了... 看看图片的地址 Codeforces可还行) 没错,珂朵莉树来自Co ...

  2. [转]我的数据结构不可能这么可爱!——珂朵莉树(ODT)详解

    参考资料: Chtholly Tree (珂朵莉树) (应某毒瘤要求,删除链接,需要者自行去Bilibili搜索) 毒瘤数据结构之珂朵莉树 在全是珂学家的珂谷,你却不知道珂朵莉树?来跟诗乃一起学习珂朵 ...

  3. Chtholly Tree (珂朵莉树) ODT

    ODT,OldDriverTree,又名ChthollyTree" role="presentation" style="position: relative; ...

  4. 珂朵莉树(Chtholly Tree)学习笔记

    珂朵莉树(Chtholly Tree)学习笔记 珂朵莉树原理 其原理在于运用一颗树(set,treap,splay......)其中要求所有元素有序,并且支持基本的操作(删除,添加,查找......) ...

  5. [数据结构]ODT(珂朵莉树)实现及其应用,带图

    [数据结构]ODT(珂朵莉树)实现及其应用,带图 本文只发布于博客园,其他地方若出现本文均是盗版 算法引入 需要一种这样的数据结构,需要支持区间的修改,区间不同值的分别操作. 一般的,我们会想到用线段 ...

  6. 洛谷$P2572\ [SCOI2010]$ 序列操作 线段树/珂朵莉树

    正解:线段树/珂朵莉树 解题报告: 传送门$w$ 本来是想写线段树的,,,然后神仙$tt$跟我港可以用珂朵莉所以决定顺便学下珂朵莉趴$QwQ$ 还是先写线段树做法$QwQ$? 操作一二三四都很$eas ...

  7. 洛谷AT2342 Train Service Planning(思维,动态规划,珂朵莉树)

    洛谷题目传送门 神仙思维题还是要写点东西才好. 建立数学模型 这种很抽象的东西没有式子描述一下显然是下不了手的. 因为任何位置都以\(k\)为周期,所以我们只用关心一个周期,也就是以下数都在膜\(k\ ...

  8. 洛谷P4344 [SHOI2015]脑洞治疗仪(珂朵莉树)

    传送门 看到区间推倒……推平就想到珂朵莉树 挖脑洞直接assign,填坑先数一遍再assign再暴力填,数数的话暴力数 //minamoto #include<iostream> #inc ...

  9. 洛谷P2787 语文1(chin1)- 理理思维(珂朵莉树)

    传送门 一看到区间推倒……推平操作就想到珂朵莉树 区间推平直接assign,查询暴力,排序的话开一个桶统计,然后一个字母一个字母加就好了 开桶统计的时候忘了保存原来的左指针然后挂了233 //mina ...

随机推荐

  1. 04.Mybatis输出映射之ResultMap

    当实体类中的字段名与数据库中的字段名不一致时需要手动设置映射关系 在Mapper.xml中定义 <!-- resultMap最终还是要将结果映射到pojo上,type就是指定映射到哪一个pojo ...

  2. CF596D Wilbur and Trees

    题意:有一些高度为h的树在数轴上.每次选择剩下的树中最左边或是最右边的树推倒(各50%概率),往左倒有p的概率,往右倒1-p. 一棵树倒了,如果挨到的另一棵树与该数的距离严格小于h,那么它也会往同方向 ...

  3. 廖雪峰Java11多线程编程-2线程同步-3死锁

    1.线程锁可以嵌套 在多线程编程中,要执行synchronized块: 必须首先获得指定对象的锁 Java的线程锁是可重入的锁.对同一个对象,同一个线程,可以多次获取他的锁,即同一把锁可以嵌套.如以下 ...

  4. 高速网络下的http协议优化

    http协议是基于TCP协议,具备TCP协议的所有功能.但是与一般TCP的长连接不同的是http协议往往连接时间比较短,一个请求一个响应了事.但是总所周知,TCP协议除了具备可靠的传输以外,还有拥塞控 ...

  5. GROUP方法也是连贯操作方法之一

    GROUP方法也是连贯操作方法之一,通常用于结合合计函数,根据一个或多个列对结果集进行分组 . group方法只有一个参数,并且只能使用字符串. 例如,我们都查询结果按照用户id进行分组统计: $th ...

  6. 0821NOIP模拟测试赛后总结

    60分rank20.挂.完. 赛时状态 不是很好.老眼混花看错无数题目信息. 倒不是很困.尽管昨天晚上为了某个该死的s-h-s-j活动报告忙到了今天,但我不得不说车上的睡眠还是挺好的. 照例通读三道题 ...

  7. Python-面向对象之封装与多态

    目录 组合 什么是组合 使用组合的目的 如何使用组合 封装 什么是封装 为什么要封装 如何封装 访问限制机制 什么是访问限制机制 访问限制机制的目的 如何使用访问限制 property 什么是prop ...

  8. sql.xml where ids in的写法

    <if test="iSurfaceTypeArray != null"> AND b.i_SurfaceType in <!-- 根据外观检查查询 --> ...

  9. coreseek 基与Sphinx 的全文索引

    假设有两张那个表,分别为articles,article_photos两张表.搜索的时候,要匹配articles.title.articles.intro.article_photos.caption ...

  10. PHP面向对象魔术方法基本了解

    简单介绍 (1) 魔术方法都是系统提供,程序员使用即可. (2) 所有的魔术方法,前面都是以  __ 开头的 _是两个下划线. (3) 我们在自定义函数时,就不要使用 __开头了. (4) 魔术方法是 ...