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

本文只发布于博客园,其他地方若出现本文均是盗版

算法引入

需要一种这样的数据结构,需要支持区间的修改,区间不同值的分别操作。

一般的,我们会想到用线段树或者Splay等支持序列操作的数据结构。但是我们这里讲引入一种更加简单的数据结构。

算法介绍

节点信息

节点定义

ODT的基本节点将保存如下信息。

  1. 该节点所代表序列的左右区间

  2. 该节点所代码的区间的值

    C++代码如下

    struct Odt_Node
    {
    int l, r;
    int val;
    };

可以发现一个ODT节点需要代表的是一块值全部相同的区间

节点信息维护

ODT基本节点可以由各种数据结构进行维护,一般我们使用C++自带的数据结构std::set。

按节点的左端点进行升序排序。这样我们就可以完整的保存一个1~n的序列信息了。

C++代码如下

inline bool operator<(const Odt_Node &a, const Odt_Node &b)
{
return a.l < b.l;
}

基本操作

操作名 含义
split(x) 把ODT节点(区间)单独分开,使得有一个子节点(区间)的左端点为x。(在x之前把区间分裂开)
assign(l,r,val) 把区间[l,r]全部赋值为val
Split实现

首先我们需要找到x点的位置。这里我们使用的是set的upper_bound函数,利用这个函数我们可以轻松的找到第一个开头大于x的区间,而x就在这个区间的前一个区间里面。

当然如果前一个区间开头刚好是x,那就可以直接返回这个区间节点对应的迭代器。

  1. 如果区间开头不是x,那就说明x在这个区间里面,我们要做的就是把这个区间分裂开。

  2. 首先我们记录我们要分裂的这个区间的左右端点,以及数值。

  3. 然后我们就可以把要分裂的这个区间节点从set里删除了。

  4. 再插入两个新节点(一个是 "L->(x-1)" 另一个是 "x->R")。

  5. 直接返回x开头的那个元素的迭代器就好了

flowchart TB
A["L->R"]-->B["L->(x-1)"]
A["L->R"]-->C["x->R"]

差不多就上面这个样子。

代码如下

inline auto split(int x)
{
if (x > n)
return S.end();
auto iter = --S.upper_bound({x, 0, 0});
if (iter->l == x)
return iter;
int l = iter->l, r = iter->r;
char v = iter->v;
S.erase(iter);
S.insert({l, x - 1, v});
return S.insert({x, r, v}).first;
}
Assign实现

Assign的作用就是区间赋值。既然我们需要进行区间赋值,那么我们就要把这个区间整出来。我们把区间的左右端点分割开了

如果从区间上看就是这样

graph LR
A["..."]-->B["L-..."].->C["..."].->D["...-(R-1)"]-->E["R-...."]-->F["..."]

这时候我们只需要把[L,R)之间的节点删除就好了。

然后插入一个新的直接[L,R)的区间节点。

有点像是把这些零零碎碎的节点直接推平重整

代码如下

inline void assign(int l, int r, char v)
{
auto itr = split(r + 1), itl = split(l);
S.erase(itl, itr);
S.insert({l, r, v});
}

特殊操作

排序算法

有时候我们不仅仅需要满足区间修改这个操作。我们可能还需要进行区间排序。

怎么实现呢?我们当然不可能在ODT里跑一个数组里的那样的排序算法,难写,而且浪费时间

我们考虑到排序操作的影响结果——就是把第几小的放到前面。

这和ODT的区间修改不谋而合。我们只需要统计出各个数的数量,然后从小到大依次修改对应的区间就好了。

至于统计出现数的数量,你可以使用桶排序(数组或者map都行)。

一般题目也是要求给一个字符串排序。

代码如下

int cnt['Z' + 1];

inline void conut(int l, int r)
{
memset(cnt, 0, sizeof cnt);
auto itr = split(r + 1), itl = split(l);
for (auto i = itl; i != itr; i++)
{
cnt[i->v] += i->r - i->l + 1;
}
} inline void sort(int l, int r)
{
conut(l, r);
int nl = l;
for (int i = 'A'; i <= 'Z'; i++)
{
assign(nl, nl + cnt[i] - 1, i);
nl += cnt[i];
}
}

[数据结构]ODT(珂朵莉树)实现及其应用,带图的更多相关文章

  1. Comet OJ - Contest #14 转转的数据结构题 珂朵莉树+树状数组

    题目链接: 题意:有两个操作 操作1:给出n个操作,将区间为l到r的数字改为x 操作2:给出q个操作,输出进行了操作1中的第x到x+y-1操作后的结果 解法: 把询问离线,按照r从小到大排序 每次询问 ...

  2. ODT珂朵莉树

    关于ODT,据说是毒瘤lxl发明的,然后毒瘤鱼鱼因为我用ODT误导人D了我一回-- 这是一种基于 \(set\) 的暴力数据结构. 在使用时请注意,没看见这2东西千万别用-- 1.保证数据随机 2.有 ...

  3. ODT 珂朵莉树 入门

    #include<iostream> #include<stdio.h> #include<string.h> #include<algorithm> ...

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

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

  5. 珂朵莉树(ODT)笔记

    珂朵莉树,又叫老司机树($Old\, Driver \, Tree$) 是一种暴力出奇迹,就怕数据不随机的数据结构. 适用 需要用线段树维护一些区间修改的信息…… 像是区间赋值(主要),区间加…… 原 ...

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

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

  7. LOJ#557. 「Antileaf's Round」你这衣服租来的吗(FHQ Treap+珂朵莉树)

    题面 传送门 题解 好吧我是不太会复杂度分析-- 我们对于每种颜色用一个数据结构维护(比方说线段树或者平衡树,代码里写的平衡树),那么区间询问很容易就可以解决了 所以现在的问题是区间修改,如果区间颜色 ...

  8. 题解 P3372 【【模板】线段树 1】(珂朵莉树解法)

    这道题可以用珂朵莉树做,但是由于数据比较不随机,而我也没有手写一颗平衡树,所以就被卡掉了,只拿了70分. 珂朵莉树是一种基于平衡树的(伪)高效数据结构. 它的核心操作是推平一段区间. 简而言之,就是把 ...

  9. 『珂朵莉树 Old Driver Tree』

    珂朵莉树 珂朵莉树其实不是树,只是一个借助平衡树实现的数据结构,主要是对于有区间赋值的数据结构题,可以用很暴力的代码很高效地完成任务,当然这是建立在数据随机的基础上的. 即使数据不是随机的,写一个珂朵 ...

随机推荐

  1. 面试题五:Spring

    Spring IoC 什么是IoC? 容器创建Bean对象,将他们装配在一起,配置并且管理它们的完整生命周期. Spring容器使用依赖注入来管理组成应用程序的Bean对象: 容器通过提供的配置元数据 ...

  2. GitLab升级(yum安装版v11.11.8~12.0.12)

    参考官方升级建议(注意升级路线:Example upgrade paths) 升级前请自行备份(测试可忽略此步骤) 生成备份文件,在/var/opt/gitlab/backups/目录下生成备份文件 ...

  3. SpringMVC(3)URL请求到Action的映射规则

    在SpringMVC(2)经典的HelloWorld实现我们展示了一个简单的get请求,并返回了一个简单的helloworld页面.本篇我们来学习如何来配置一个action的url映射规则. 在Spr ...

  4. [NOI2000] 古城之谜

    题目描述 给定 n 和 n 个信息,每个信息包含一个词性 a (只有三种:名,动,辅)和对应的词 mot ,形为" \(a.mot\) ".(一次可能多词性) 最后给一个长度不大于 ...

  5. 从零搭建一个IdentityServer——资源与访问控制

    IdentityServer作为授权服务器它的最终目的是用于对资源进行管控,这里所说的资源有两种,其一是API资源,实际上也就是OIDC协议中客户端(RP)所需要访问的一系列受保护的资源(API),授 ...

  6. VUE+ElementUI实现左侧为树形结构、右侧无层级结构的穿梭框

    工作中遇到一个需求,需要将一个数据选择做成穿梭框,但是要求穿梭框左侧为树形结构.右侧为无层级结构的数据展示,ElementUI自身无法在穿梭框中添加树形结构,网上搜到了大佬封装的插件但是对于右侧的无树 ...

  7. Java多线程(下)

    线程同步 当多个线程访问一个对象时,有可能会发生污读,即读取到未及时更新的数据,这个时候就需要线程同步. 线程同步: 即当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线 ...

  8. String类型转成int类型

    在将String类型转换成int类型时: int n = Interger.parseInt(Stringnum); 如果报错,可以改成 int n = Interger.parseInt(Strin ...

  9. jenkens安装教程

    war包安装方式(linux和windows下) 具体参见:https://www.cnblogs.com/UncleYong/p/10742867.html

  10. 🔥 LeetCode 热题 HOT 100(61-70)

    207. 课程表 思路:根据题意可知:当课程之间不存在 环状 循环依赖时,便能完成所有课程的学习,反之则不能.因此可以将问题转换成: 判断有向图中是否存在环.使用 拓扑排序法 : 构建 入度表:记录每 ...