[转]我的数据结构不可能这么可爱!——珂朵莉树(ODT)详解
参考资料:
Chtholly Tree (珂朵莉树) (应某毒瘤要求,删除链接,需要者自行去Bilibili搜索)
在全是珂学家的珂谷,你却不知道珂朵莉树?来跟诗乃一起学习珂朵莉树丫~
(挑战用最短的篇幅讲清楚一个毒瘤数据结构)
1、珂朵莉是什么?
珂朵莉·诺塔·瑟尼欧里斯是轻小说及改编动画《末日时在做什么?有没有空?可以来拯救吗?》中的女主角,五位成体妖精兵之一。最强圣剑“瑟尼欧里斯”的适合者。在第28号浮游岛上意外跌落而与威廉相遇,并受到他的帮助。 但是知道了珂朵莉对你学习珂朵莉树并没有什么帮助。
2、珂朵莉树是什么?
珂朵莉树又称老司机树(Old Driver Tree),可能是因为发明者是一个珂学家所以发明了这个数据结构?
废话到此结束。
珂朵莉树是基于C++STL库中的set的数据结构。与线段树、平衡树等树形结构类似,珂朵莉树是用来解决区间问题的很暴力的树形结构。
特色:珂朵莉树支持区间推平(将区间$L$~$R$全部赋值为同一个值$x$)
3、在学习之前你需要知道:set(若熟悉此STL请跳过)
set的本质是一棵平衡树。特性为插入到set中的元素会被自动排序并且不允许set中有相同的元素。
珂朵莉树中需要用到的函数:
set <Node> t; //定义一个名为t,类型为Node(结构体)的set
s.begin(); //返回指向第一个元素的迭代器(地址)
s.end(); //返回指向最后一个元素的迭代器
s.clear(); //清空s
s.insert(a); //将a插入到s
s.erase(l, r);//将迭代器l~r之间的元素全部删除
s.lower_bound(a); //二分查找a在s中的位置,返回一个迭代器。
set<Node>::iterator pos; //定义一个迭代器pos。
4、珂朵莉树可以解决什么问题?
当我们需要推平一段区间时,可以使用珂朵莉树。珂朵莉树高效的基础是数据随机生成。也就是说,这个数据结构很容易被构造数据卡掉。但是在珂朵莉树依然鲜为人知的现在又有谁会去构造数据去卡一个知名度并不高的算法呢?你都愿意学SPFA了不是吗
来看一道例题:
CF869C Willem, Chtholly and Seniorious
题目大意:
我有一个可爱的序列。你需要编写程序支持以下操作:
1 l r x :将[l,r]区间所有数加上x
2 l r x :将[l,r]区间所有数改成x
3 l r x :输出将[l,r] 区间从小到大排序后的第x个数是的多少
4 l r x y :输出[l,r] 区间每个数字的$x$次方的和模y的值
5、珂朵莉树的构造
其实珂朵莉树被称作“树”大概仅仅是因为使用了set吧。在学习珂朵莉树时,你大可以不把它作为一个树来理解。
珂朵莉树的每一个节点由一个三元组(l, r, val)组成,表示区间$[l,r]$之间的值全是x。
例子: 我有一个可爱的序列:
1 1 1 1 1 2 2 2 2 3 3 3 3
则在珂朵莉树上这个序列被表示为(1, 5, 1) (6, 9, 2) (10, 14, 3)三个节点。
建树实现:
struct node {
int l, r;//区间左端点与右端点。
mutable lint v;//mutable为“可变的”,使我们可以直接修改v的值
node(int L, int R = -1, lint V = 0) : l(L), r(R), v(V) {}
bool operator < (const node &o) const {
return l < o.l;
}
}; //定义一个结构体,重载<为按左端点排序。
set <node> s;//扔到set里
是不是非常的简单好懂鸭?
6、核心操作:区间分割
考虑刚刚那个可爱的序列:
1 1 1 1 1 2 2 2 2 3 3 3 3
现在我要强人锁男将2~13这个区间全部加上1。
前文提到,在珂朵莉树上这个序列被表示为(1, 5, 1) (6, 9, 2) (10, 14, 3)三个节点。也就是说我们根本没有办法直接对2~13这个区间加上1.
这个时候如果我们将(1, 5, 1) (6, 9, 2) (10, 14, 3)三个区间分割为(1, 1, 1) (2, 5, 1) (6, 9, 2) (9, 13, 3) (14, 14, 3)这几个区间就可以直接对区间2~13中所对应的节点直接进行操作啦!超快乐!
∴现在我们需要写一个函数spilit(pos),将pos所在的节点以pos为中心分为两个节点。
实现步骤:
- 找到pos所在的节点(l, r, val)
- 删掉这个节点
- 把这个节点变成(l, pos-1, val)和(pos, r, val)扔回set。
- 返回右区间迭代器(以后有用)
代码实现:
#define IT set<node>::iterator
//迭代器宏定义
IT spilit (int pos) {
IT it = s.lower_bound(node(pos, -1, 0));//找到第一个l不小于pos的节点
if(it != s.end() && it->l == pos) return it;//不需要分割直接退出
it--;//pos一定在前一个区间中
int L = it -> l, R = it -> r;
lint V = it->v;
s.erase(it);//删了
s.insert(node(L, pos-1, V));//左区间丢进去
return s.insert(node(pos, R, V)).first;//右区间丢进去,返回右区间的迭代器。
}
是不是特别简单?
7、降低复杂度的关键:区间赋值(推平)
实现步骤: 设要推平的区间为[l, r]。
- 把l和r所在的节点分割。
- 把要推平的区间[l, r]之间的节点全部删掉。
- 把(l, r, val)扔进set
没了。诗乃觉得没有什么需要解释的了。
#define IT set<node>::iterator
void tp(int l, int r, int val) {
IT il = spilit(l), ir = spilit(r+1);
s.erase(il, ir);
s.insert(node(l, r, val));
}
8、当我们要对一段区间进行操作时:
设要操作的区间为[l, r]。
我们先把l和r所在的节点分割,暴力对区间[l, r]中的节点一个个取出来操作(修改或统计答案)即可,反正没有多少节点。这个东西视具体题目而定,这里不再赘述。
例子:区间加
#define IT set<node>::iterator
void add(int l, int r, int val) {
IT il = spilit(l), ir = spilit(r+1);
for(; il != ir; il->v += val, il++);
}
9、我最喜欢暴力数据结构了。
惊不惊喜?现在你已经学会珂朵莉树了,可以做一做例题练一下手呢。(是NOI+/CTSC难度的黑题哦)。
其他例题: CF915E 、bzoj4293(权限题)
珂朵莉树的优点:码量少,好理解,调错快。
缺点:在数据随机的时候推平操作比较多,所以它的复杂度会趋近于mlogn(m为询问次数)。但当出题人想要卡珂朵莉树时肯定会T飞。珂朵莉这么可爱谁会卡呢
10、我永远喜欢珂朵莉!
[转]我的数据结构不可能这么可爱!——珂朵莉树(ODT)详解的更多相关文章
- [数据结构]ODT(珂朵莉树)实现及其应用,带图
[数据结构]ODT(珂朵莉树)实现及其应用,带图 本文只发布于博客园,其他地方若出现本文均是盗版 算法引入 需要一种这样的数据结构,需要支持区间的修改,区间不同值的分别操作. 一般的,我们会想到用线段 ...
- Comet OJ - Contest #14 转转的数据结构题 珂朵莉树+树状数组
题目链接: 题意:有两个操作 操作1:给出n个操作,将区间为l到r的数字改为x 操作2:给出q个操作,输出进行了操作1中的第x到x+y-1操作后的结果 解法: 把询问离线,按照r从小到大排序 每次询问 ...
- 数据结构31:树(Tree)详解
复制广义表数据结构中的树 树是数据结构中比较重要也是比较难理解的一类存储结构.本章主要主要围绕二叉树,对树的存储以及遍历做详细的介绍,同时还会涉及到有关树的实际应用,例如构建哈弗曼编码等. 由于树存储 ...
- Redis数据结构详解之List(二)
序言 思来想去感觉redis中的list没什么好写的,如果单写几个命令的操作过于乏味,所以本篇最后我会根据redis中list数据类型的特殊属性,同时对比成熟的消息队列产品rabbitmq,使用red ...
- 数据结构图文解析之:队列详解与C++模板实现
0. 数据结构图文解析系列 数据结构系列文章 数据结构图文解析之:数组.单链表.双链表介绍及C++模板实现 数据结构图文解析之:栈的简介及C++模板实现 数据结构图文解析之:队列详解与C++模板实现 ...
- 数据结构图文解析之:AVL树详解及C++模板实现
0. 数据结构图文解析系列 数据结构系列文章 数据结构图文解析之:数组.单链表.双链表介绍及C++模板实现 数据结构图文解析之:栈的简介及C++模板实现 数据结构图文解析之:队列详解与C++模板实现 ...
- 数据结构图文解析之:二叉堆详解及C++模板实现
0. 数据结构图文解析系列 数据结构系列文章 数据结构图文解析之:数组.单链表.双链表介绍及C++模板实现 数据结构图文解析之:栈的简介及C++模板实现 数据结构图文解析之:队列详解与C++模板实现 ...
- 数据结构图文解析之:哈夫曼树与哈夫曼编码详解及C++模板实现
0. 数据结构图文解析系列 数据结构系列文章 数据结构图文解析之:数组.单链表.双链表介绍及C++模板实现 数据结构图文解析之:栈的简介及C++模板实现 数据结构图文解析之:队列详解与C++模板实现 ...
- redis 五种数据结构详解(string,list,set,zset,hash)
redis 五种数据结构详解(string,list,set,zset,hash) Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存 ...
随机推荐
- composer require 本地包(用于开发使用)
修改 composer.json "repositories": [ { "type": "path", "url": ...
- springboot的日志框架slf4j (使用logback输出日志以及使用)
1.为什么使用logback? ——在开发中不建议使用System.out因为大量的使用会增加资源的消耗.因为使用System.out是在当前线程执行的,写入文件也是写入完毕之后才继续执行下面的程序. ...
- WEB前端技巧之JQuery为动态添加的元素绑定事件.md
jquery 为动态添加的元素绑定事件 如果直接写click函数的话,只能把事件绑定在已经存在的元素上,不能绑定在动态添加的元素上 可以用delegate来实现 .delegate( select ...
- Java中多个异常的捕获顺序(多个catch)
import java.io.IOException; public class ExceptionTryCatchTest { public void doSomething() throws IO ...
- Linux命令(五)免密码远程登录和配置别名
1. ssh-keygen 2. ssh-copy-id -p port user@remote .ssh中建立并编辑config文件 原来需要 ssh -p ubuntu@xxx.xxx.xxx 现 ...
- 【原创】backbone1.1.0源码解析之Collection
晚上躺在床上,继续完成对Backbone.Collection的源码解析. 首先讲讲它用来干嘛? Backbone.Collection的实例表示一个集合,是很多model组成的,如果用model比喻 ...
- CSS-3 圆角Border-radius 的使用
那么早些年 圆角其实是有的,后来的草案中将它去掉了,现在从CSS3开始,又加入了回来.可以看出圆角的使用还是非常广泛的. 那么在圆角还没有被加入进来之前,我们要实现圆角的效果,可能就是需要IMG图片来 ...
- HDU 2521 反素数 模拟题
解题报告:水题,直接附上代码,只是觉得这题的作者是不是吃饱了饭撑的,反素数的概念跟这题一点关系都没有. #include<cstdio> int judge1(int k) { ; ;i& ...
- 转载一篇介绍CUDA
鉴于自己的毕设需要使用GPU CUDA这项技术,想找一本入门的教材,选择了Jason Sanders等所著的书<CUDA By Example an Introduction to Genera ...
- slf4j MDC使用
slf4j MDC使用 最近也是在项目代码里发现一个地方有个MDC.put(),忍不住好奇点了进去,于是知道了MDC这个东西,细研究一下,发现还真是个好东西. MDC解决了什么问题 MDC全名Mapp ...