[转]我的数据结构不可能这么可爱!——珂朵莉树(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等数据结构的存 ...
随机推荐
- python---redis管道(事务)和发布订阅
管道:将数据操作放在内存中,只有成功后,才会一次性全部放入redis #管道(事务),要是都成功则成功,失败一个全部失败 #原理:将数据操作放在内存中,只有成功后,才会一次性全部放入redis pip ...
- idea2017破解方法
破解方法 切换license server然后 输入网址:http://idea.iteblog.com/key.php即可
- hdu 5079 Square
http://acm.hdu.edu.cn/showproblem.php?pid=5079 题意: n*n网格,每个格子可以涂黑色或白色,有的格子必须涂黑色 问最大白色正方形边长分别为0,1,2,… ...
- Docker学习笔记四 Docker容器
本文地址:https://www.cnblogs.com/veinyin/p/10439849.html 容器是独立运行的一个或一组应用及他们的运行态环境,对应虚拟机的操作系统和应用. 启动 可 ...
- NIO学习(1)-入门学习
一.NIO概念 IO:标准IO,也既阻塞式IO NIO:非阻塞式IO 二.NIO与标准IO的IO工作方式 标准IO基于字节流和字符流进行操作 NIO是基于通道(Channel)和缓冲区(Buffer) ...
- Codeforces 238 div2 A. Gravity Flip
题目链接:http://codeforces.com/contest/405/problem/A 解题报告:有n列箱子竖直放置,每列箱子上都有数量不等的箱子,这些箱子之间没有固定,当重力方向改为平行向 ...
- CodeAction_beta02 斐波那契 (多维DP)
题面: solution: 这题和斐波那契数列没有任何关系!!!!! 这题就是一个无脑DP!!!!!!!!!! 因为所有数都要出现至少一次,所以只需考虑其组合而不用考虑其排列,最后乘个 n!就是了(意 ...
- 2017/05/22 java 基础 随笔
多态:一种事物多种形态 前提:1.子父类继承关系 2.方法复写.重写 3.父类引用指向子类对象 成员变量: package com.huawei; public class Demo1 { publi ...
- Mycat 配置及优化【转】
前言 Mycat 是一个数据库分库分表中间件 MyCAT 是作为通用代理设计的,后端是以 Mysql协议 和 JDBC 的方式连接数据库,可以支持 Oracle.DB2.SQL Server . mo ...
- 安装.NET Framework返回1603错误的解决办法
昨天正在忙其它事情,实然同事向我反馈TFS上的文档无法浏览查看.第一反映是他的机器环境问题,让他试了下其它项目的文档也无法查看,后来在我电脑上也尝试了一下,果然无法查看项目文档,看来是TFS出了问题. ...