珂朵莉树

(珂学)

珂朵莉树(或者老司机树)起源于CF896C。
由于之前做到每一组数据都要另外开数据结构,所以现在一些东西就会写为class包装

前置知识点

  • STL中set的使用(list也行,但是效率差点)

    • set的排序规则
    • insert
    • erase
    • lower_bownd
  • 暴力

使用

珂朵莉树通过直接对区间进行暴力维护。不同于线段树或者树状数组对于区间的维护,珂朵莉树相当于直接把区间拆出来进行修改。

下面的代码基于CF896C。

定义

珂朵莉树的定义如下:

// using ll = long long;
class ODT {private:class Node {int l, r;mutable ll val;Node(int l = 0, int r = 0, ll val = 0) : l(l), r(r), val(val) {}bool operator < (const Node &a) const {return l < a.l;}};set<Node>tr;public:void insert(int l, int r, int val);auto split(int pos);void assign(int l, int r, ll val);auto work(int l, int r, ...);
};

珂朵莉树是对区间的暴力维护,需要重载小于号(或者写个比较函数,只要像上面那个一样就行)(Node是想不到名字就起的,也可以改为Segment)。而后面的set就是珂朵莉树的核心。

关于mutable关键字

mutable意为可变的,也就是说,加上这个关键字可以直接对里面的val进行修改,而无需清除再插入

下面还有几个操作。

insert

其实这个操作仅仅是把区间插入set里面(因为没有的区间要插入),不过因为用class包装所以需要多一个insert。

void ODT::insert(int l, int r, int val) {tr.insert(Node(l, r, val));
}

split

珂朵莉树的第一个核心操作。

这个操作就是直接暴力的把一个区间(根据区间左端点)拆出来。

auto ODT::split(int pos) {auto it = tr.lower_bownd(Node(pos));// 找到一个有效的区间,而且这个区间左端点刚好是位置if (it != tr.end() && it->l == pos) {return it;}// 到这里,说明找的区间位置偏右了点-- it;int l = it->l, r = it->r;ll val = it->val;// 暴力分裂tr.erase(it);tr.insert(Node(l, pos - 1, val));return tr.insert(Node(pos, r, val)).first;
}

set的insert操作的first

set的insert操作中会返回一个pair。其中first为指向插入内容的迭代器。由于分裂的目的就是为了提出左端点为pos的区间,所以要返回这个玩意。

assign

这个是珂朵莉树的第二个关键操作。

这个操作就是简单暴力地,将l到r范围内的所有区间暴力删掉,然后新建一个区间l到r,值改为val

void ODT::assign(int l, int r, ll val) {auto end = split(r + 1), begin = split(l);tr.erase(begin, end);  // 这个可以清除[begin, end)范围内的区间tr.insert(Node(l, r, val));
}

work

这个操作其实就是一些附加操作。大致都是直接暴力找到区间进行操作。所以会有大致的模板。

auto ODT::work(int l, int r, ...) {auto itr = split(r + 1), itl = split(l);for (; itl != itr; ++ itl) {// work}
}

总结

珂朵莉树就是这样一个暴力的操作过程。当然,如果set里面的区间非常多,就退化成了完全的暴力。所以,在数据随机的情况下,珂朵莉树的效果很好,反之也可以很简单的构造出数据卡爆珂朵莉树。

因此,珂朵莉树可以用在:区间修改特定一个值(还有骗分)。

例题

CF896C

相比于上面的模板,起源题多了三个操作,也就是work的拓展。

这个暴力实在是太优美了

下面的代码也相当于模板了。

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define all(x) std::begin(x), std::end(x)
inline ll mul(ll a, ll b, ll p) {return static_cast<__int128_t>(a) * b % p;
}
inline ll power(ll a, ll i, ll p) {ll res = 1;while (i) {if (i & 1)res = mul(res, a, p);a = mul(a, a, p);i >>= 1;}return res;
}
class ODT {private:struct Node {int l, r;mutable ll val;Node(int l = 0, int r = 0, ll val = 0) : l(l), r(r), val(val) {}bool operator < (const Node &a) const {return l < a.l;}};set<Node>odt;public:void insert(int l, int r, ll val) {odt.insert(Node(l, r, val));}auto split(int pos) {auto it = odt.lower_bound(Node(pos));if (it != odt.end() && it->l == pos)return it;-- it;int l = it->l, r = it->r;ll val = it->val;odt.erase(it);odt.insert(Node(l, pos - 1, val));return odt.insert(Node(pos, r, val)).first;}void assign(int l, int r, ll val) {auto end = split(r + 1), begin = split(l);odt.erase(begin, end);odt.insert(Node(l, r, val));}void add(int l, int r, ll k) {  // 暴力拿出区间求和auto itr = split(r + 1), itl = split(l);for (; itl != itr; ++ itl) {itl->val += k;}}ll rank(int l, int r, int kth) {  // 暴力排序,一个一个数vector<pair<ll, int>>v;auto itr = split(r + 1), itl = split(l);for (; itl != itr; ++ itl) {v.push_back({itl->val, itl->r - itl->l + 1});}sort(all(v), [](const pair<ll, int>&a, const pair<ll, int>&b) {return a.first != b.first ? a.first < b.first : a.second < b.second;});for (const auto &[val, cnt] : v) {kth -= cnt;if (kth <= 0) {return val;}}return -1;}ll sum(int l, int r, ll k, ll p) {  // 暴力拿出区间,一个一个计算ll res = 0;auto itr = split(r + 1), itl = split(l);for (; itl != itr; ++ itl) {res = (res + mul(power(itl->val, k, p), itl->r - itl->l + 1, p)) % p;}return res;}
};

P2572 [SCOI2010] 序列操作

这道题卡珂朵莉树,不过可以试着用珂朵莉树做做。

和上面的题相比,多了区间取反、计算1的个数和计算最长1的长度。暴力就可以有30分,然后其他都是TLE。

class ODT {private:struct Node {int l, r;mutable int val;Node(int l = 0, int r = 0, int val = 0) : l(l), r(r), val(val) {}bool operator < (const Node &a) const {return l < a.l;}};set<Node>tr;public:void insert(int l, int r, int val) {tr.insert(Node(l, r, val));}auto split(int pos) {auto it = tr.lower_bound(Node(pos));if (it != tr.end() && it->l == pos) {return it;}-- it;int l = it->l, r = it->r, val = it->val;tr.erase(it);tr.insert(Node(l, pos - 1, val));return tr.insert(Node(pos, r, val)).first;}void assign(int l, int r, int val) {auto end = split(r + 1), begin = split(l);tr.erase(begin, end);tr.insert(Node(l, r, val));}void XOR(int l, int r) {auto itr = split(r + 1), itl = split(l);for (; itl != itr; ++ itl) {itl->val ^= 1;}}int sum(int l, int r) {int ans = 0;auto itr = split(r + 1), itl = split(l);for (; itl != itr; ++ itl) {if (itl->val) {ans += itl->r - itl->l + 1;}}return ans;}int maxlen(int l, int r) {int ans = 0;auto itr = split(r + 1), itl = split(l);vector<pair<int, int>>v;for (; itl != itr; ++ itl) {if (v.empty() || v.back().first != itl->val) {v.push_back({itl->val, itl->r - itl->l + 1});} else {v.back().second += itl->r - itl->l + 1;                    }if (!v.empty() && v.back().first) {ans = max(ans, v.back().second);}}return ans;}
};

【日志】珂学——珂朵莉树相关推荐

  1. CF896C Willem, Chtholly and Seniorious(珂朵莉树)

    中文题面 珂朵莉树的板子--这篇文章很不错 据说还有奈芙莲树和瑟尼欧里斯树-- 等联赛考完去学一下(逃 1 //minamoto 2 #include<bits/stdc++.h> 3 # ...

  2. codeforces 915 E 896 C 珂朵莉树

    珂朵莉树(Chtholly Tree),一种基于std::set的暴力数据结构,是由某毒瘤在2017年的一场CF比赛中提出的数据结构,原名老司机树(Old Driver Tree,ODT).由于第一个 ...

  3. 浅谈珂朵莉树(Chtholly Tree)——暴力而玄学的数据结构

    关于它很珂学的名字- 珂朵莉树(Chtholly Tree),又称老司机树(Old Driver Tree),起源于CodeFoeces平台上编号为896C的一道题-- " Willem, ...

  4. 珂朵莉树(永远喜欢珂朵莉/doge)

    目录 前言 可能用到前置知识 背景 构建珂朵莉树 核心函数 珂朵莉树在实际题目使用 对珂朵莉树的一些感想 最后的最后 前言 最近刚刚学内容大概是借鉴的吧,感觉这个数据结构不仅简单,还很强,有着非常柯学 ...

  5. CodeForces - 897E Willem, Chtholly and Seniorious(珂朵莉树)

    题目链接:点击查看 题目大意:给出一个长度为 nnn 的数列,现在需要执行 mmm 次操作,每次操作分为下列四种情况: 1lrx1 \ l \ r \ x1 l r x:[l,r][l,r][l,r] ...

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

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

  7. CF915E Physical Education Lessons(珂朵莉树)

    中文题面 据说正解是动态开点线段树而且标记也不难下传的样子 然而这种区间推平的题目还是喜欢写珂朵莉树啊--码量小-- 虽然真要构造的话随便卡-- 1 //minamoto 2 #include< ...

  8. 算法自学__珂朵莉树

    参考资料: https://zhuanlan.zhihu.com/p/106353082 https://blog.csdn.net/CC_dsm/article/details/98166835 珂 ...

  9. 一种黑科技:珂朵莉树

    首先要明白的是:珂朵莉树(ODT)是一种用来骗分的暴力数据结构. 珂朵莉树的思想是利用集合set,把相同且连续的元素合并为一个个区间,从而进行区间修改:因此,珂朵莉树是区间的集合,这点可以通过定义结构 ...

最新文章

  1. Selenium 2.0的由来及设计架构(三)
  2. Maltego发布新版本4.2.18
  3. ngrok布置外网访问环境
  4. 设计模式之Builder模式 (C++实现)
  5. java代码执行linux命令_怎么用java代码运行linux命令
  6. WPF XMAL获取元素的父元素,子元素
  7. amos调节变量怎么画_结构方程模型建模思路及Amos操作--调节变量效果确定(二)...
  8. GitHub客户端使用
  9. serialVersionUID 问题处理
  10. MongoDB官网下载和安装(ZIP安装)
  11. DDCTF2018-黑盒破解 详细WP
  12. 【LeetCode】274. H指数
  13. Git:不同仓库之间的cherry-pick
  14. [转贴] 扫盲转贴:Rootkit技术发展史
  15. 【SSD】自动化测试框架
  16. 计算机视觉博士去向,为什么现在不看好 CV 方向了呢?
  17. 爬虫:一种打破3000套限制爬取所有链家二手房源的方法
  18. 查看kafka的topic清单以及topic的内容
  19. mysql数据库errorCode 1045, state 28000
  20. lcd12864使用c语言pic单片机,PIC单片机+LCD12864显示汉字程序

热门文章

  1. 射频无源器件测试方法介绍
  2. 4 个 JavaScript 最基础的问题 —— Eric Elliott
  3. altera 设计--仿真--下载
  4. 看诸葛亮是如何识别对付小人的~
  5. Spring入门——控制反转是什么鬼
  6. 本科课程【数字图像处理】实验2 - 图像增强
  7. 逐步搜索法的matlab,逐步扫描法(搜索解区间)
  8. java gis 最短路径_用Postgis算最短路径(在任意位置选择起点终点)(下)
  9. 手机内存卡转化linux,怎样把手机内存移至sd内存卡
  10. 每日一句功能简单实现