珂朵莉树/ODT 学习笔记
珂朵莉树/ODT 学习笔记
起源自 CF896C。珂朵莉yyds!
核心思想
把值相同的区间合并成一个结点保存在 set 里面。
用处
骗分。只要是有区间赋值操作的数据结构题都可以用来骗分。在数据随机的情况下一般效率较高,但在不保证数据随机的场合下,会被精心构造的特殊数据卡到超时。
如果要保证复杂度正确,必须保证数据随机。详见 Codeforces 上关于珂朵莉树的复杂度的证明。
更详细的严格证明见 珂朵莉树的复杂度分析。对于 add,assign 和 sum 操作,用 set 实现的珂朵莉树的复杂度为 O(nloglogn)O(n \log \log n)O(nloglogn),而用链表实现的复杂度为 O(nlogn)O(n \log n)O(nlogn)。
正文
存储:每个树上节点都是一个区间,因为权值相同,于是要记录 l,r,vall,r,vall,r,val 。
struct node{I l,r;mutable int val;//可变的 val ,这么写是习惯,为了后续修改/访问操作friend bool operator <(node a,node b){return a.l<b.l;}//在 set 里面,应该比较区间左端点。以便之后查找区间并且 split 。
};set<node>s;
核心操作:split ,含义:把原来为 [l,r] 的这个节点分离成 [l,x) [x,r] ,并且返回这个 [x,r] 区间的迭代器。(可以直接使用 lower_bound)
auto split(I x){auto it=s.lower_bound({x,0,0});//在 set 之中查找 x ,因为只比较左端点所以另外两项可以随便填if(it!=s.end()&&it->l==x)return it;//如果正好找到了一个左端点为 x 的就直接返回。--it;auto p=*it;s.erase(it);//迭代器向左移动一位的区间才有可能被分裂,用 p 记录该迭代器,并且删除现在代表的区间s.insert(node{p.l,x-1,p.val});//把这个区间(存在 p 里面了)分裂return s.insert(node{x,p.r,p.val}).first;//同上,返回右边所指的迭代器,insert 的返回值是一个 pair ,它的返回值 first 是迭代器,second 是一个 bool ?
}
核心操作:assign,含义:把区间 [l,r] 赋值成为 val 。
void assign(I l,I r,I x){auto itr=split(r+1),itl=split(l);//先分裂出 [r+1,+inf] 的右边界,才能分离出 [l,r] 的可行部分,itl->l 就是 l(这个写分裂合并数据结构的大概都知道)s.erase(itl,itr);//这个是前闭后开的,删除了 itl...itr-1 的区间、迭代器s.insert(node{l,r,x});//插入一个全新的区间
}
普通操作:直接从左往右遍历珂朵莉树。
void count(I l,I r){auto itr=split(r+1),itl=split(l);for(;itl!=itr;++itl)//这个也是前闭后开的//do something...
}
习题
P4979 矿洞:坍塌
做法
做这道题先来练手。
首先区间推平只需要 assign 即可。
单点查询?只需在 set 之中二分位置即可。
判断区间颜色是否单一?只需按照上文 count
操作即可。(还有点小优化:如果合法就可以直接统一为一个区间)
CF1638E Colorful Operations
区间颜色推平;全局某种颜色所有数的加上一个数;单点查询权值。
做法
首先观察因为颜色是不连续的区间,所以不可能一个个去查找并给它加上权值。
于是就给颜色 ttt 打上标记 bz[t]bz[t]bz[t] 表示当前 ttt 颜色在操作之中累加到了多少,因为不断更新很费事。
而 aaa 数组就缓慢更新,只有改变了颜色才更新,这样一个节点的真实值就是 a[i]+bz[col[i]]a[i]+bz[col[i]]a[i]+bz[col[i]] 。
如何求一个 ppp 从 ccc 颜色修改至 c′c'c′ 颜色对其答案的贡献呢?
因为它的真实值是 a[i]+bz[c]a[i]+bz[c]a[i]+bz[c] ,所以先算了 bz[c]bz[c]bz[c] 的帐,即加上 bz[c]bz[c]bz[c] ;
但是它不能直接存储真实值,所以要减去 bz[c′]bz[c']bz[c′] 。
在 ODT 上每个节点都是一段区间,所以考虑使用树状数组维护。
总而言之,操作1就珂朵莉树上面的 assign 操作和区间加;操作2直接 O(1) 改变标记;操作3就直接树状数组查询权值+珂朵莉树查询颜色。
CF343D Water Tree
做法
观察到本题只有区间推平和单点查询操作,所以珂朵莉树维护。
树上的操作通过树剖即可解决。
6362.【NOIP2019模拟2019.9.18】数星星(star)
题意:给 nnn 个点有点权,有 mmm 条路径,有 qqq 次操作查询 [l,r][l,r][l,r] 条路径的并的点权之和是多少。
(编者强烈建议搞定 CF343D 和 CF1638E 再来处理本题)
做法
看这么一个东西:HH的项链,就是区间统计个数,相同的只统计一次。
因为可以离线,所以按照 rrr 递增排序,不断加入 rrr ,然后更新一下每个数最后出现在哪里(其实就是权值等于 a[r]a[r]a[r] 的数)。对于 [l,r][l,r][l,r] 询问,查询最晚出现位置大于 l−1l-1l−1 的数的个数。
然后考虑迁移到这题之中:也是离线下来,按照 rrr 递增排序,不断加入 rrr ,然后更新一下每个点最后出现在第几个询问。对于 [l,r][l,r][l,r] 依旧是查询最晚出现位置大于 l−1l-1l−1 的点。对于一条路径更新路径上所有点的最晚出现位置,查询所有最晚出现位置大于 l−1l-1l−1 的点权之和。
再写得显然一些,树链剖分之后(即在 dfs 序上做区间操作),区间推平;查询大于等于 lll 的数的权值之和(可以转化成小于等于 l−1l-1l−1 数的个数,初始出现位置 000 就好)。
这个大于等于 lll 的数的点权之和就可以直接丢进树状数组里面处理;对于区间推平,直接使用 ODT 维护即可。因为 ODT 把每个区间压缩成为了一个点,所以加减的话也要直接加减这个区间的点权之和。因为是被推平,所以要减去之前的贡献,增加现在的贡献(和 CF1638E 一样)。
实现就显而易见了。
课后练习题
CF896C Willem, Chtholly and Seniorious 万 恶 之 源
CF915E Physical Education Lessons 比模板题还简单 都是暴力有什么难的
CF817F MEX Queries 和上题差不多,但是值域超大,珂朵莉树能做
P5350 序列 平衡树的题和珂朵莉树有什么关系?
CF1423G Growing flowers *3500?*800!
珂朵莉树/ODT 学习笔记相关推荐
- [python刷题模板] 珂朵莉树 ODT (基于支持随机访问的跳表
[python刷题模板] 珂朵莉树 ODT (基于支持随机访问的跳表) 一. 算法&数据结构 1. 描述 2. 复杂度分析 3. 常见应用 4. 常用优化 二. 模板代码 0. 区间推平(lg ...
- [python刷题模板] 珂朵莉树 ODT(20220928弃用,请看新文)
[python刷题模板] 珂朵莉树 ODT (基于SortedList 20220928弃用,请看新文) 一. 算法&数据结构 1. 描述 2. 复杂度分析 3. 常见应用 4. 常用优化 二 ...
- [转]我的数据结构不可能这么可爱!——珂朵莉树(ODT)详解
参考资料: Chtholly Tree (珂朵莉树) (应某毒瘤要求,删除链接,需要者自行去Bilibili搜索) 毒瘤数据结构之珂朵莉树 在全是珂学家的珂谷,你却不知道珂朵莉树?来跟诗乃一起学习珂朵 ...
- 浅谈珂朵莉树(ODT)
前言 珂学家狂喜( 文章目录 前言 一.珂朵莉树来源 二.珂朵莉树 1.珂朵莉树有什么用? 2.原理是什么? a.存储 b.分割结点 c.推平 d.剩余操作 3.复杂度分析 三.珂朵莉树例题 1.P4 ...
- 珂朵莉树(odt老司机树)
传送门 题意:对于一段区间一共有四种操作: 题解:珂朵莉树板题 珂朵莉树,又称Old Driver Tree(ODT).是一种基于std::set的暴力数据结构. 关键操作:推平一段区间,使一整段区间 ...
- Chtholly Tree (珂朵莉树) ODT
ODT,OldDriverTree,又名ChthollyTree O D T , O l d D r i v e r T r e e , 又 名 C h t h o l l y T r e e ODT ...
- 算法自学__珂朵莉树
参考资料: https://zhuanlan.zhihu.com/p/106353082 https://blog.csdn.net/CC_dsm/article/details/98166835 珂 ...
- 【日志】珂学——珂朵莉树
珂朵莉树 (珂学) 珂朵莉树(或者老司机树)起源于CF896C. 由于之前做到每一组数据都要另外开数据结构,所以现在一些东西就会写为class包装 前置知识点 STL中set的使用(list也行,但是 ...
- 一种黑科技:珂朵莉树
首先要明白的是:珂朵莉树(ODT)是一种用来骗分的暴力数据结构. 珂朵莉树的思想是利用集合set,把相同且连续的元素合并为一个个区间,从而进行区间修改:因此,珂朵莉树是区间的集合,这点可以通过定义结构 ...
最新文章
- 给一个ul列表中点击到的li赋予样式
- 机器学习中的EM算法具体解释及R语言实例(1)
- TensorFlow2简单入门-三维张量
- Windows 10安装CUDA10.1+cudnn7.6.0+Pytorch1.3.0
- 在MFC中添加用户自定义消息
- 女孩子应该养成的好习惯
- c#打印,输出一句话
- Android开发入门二之AndroidManfest.xml文件详细说明 .
- 记一次mongdb搭建复制集的小故障
- services.xml应该放在项目的哪里_新轮胎应该放在前轮还是后轮?
- 转帖:Three Ways to Inject Your Code into Another Process
- Quartz-第四篇 常规quartz的使用
- 自定义Toast的出现样式
- C#打印代码运行时间
- Microsoft Office Visio 2007 简体中文专业版
- CAN和CAN FD
- C#使用Socket实现一个socket服务器与多个socket客户端通信
- 翻译官方Vellum教程:Breaking and tearing(破裂撕开)
- 关于jmstudio 调用本地摄像头的问题
- 计算机无法打开这个应用,win10照片应用打不开提示“无法打开这应用”如何解决...