【日志】珂学——珂朵莉树
珂朵莉树
(珂学)
珂朵莉树(或者老司机树)起源于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;}
};
【日志】珂学——珂朵莉树相关推荐
- CF896C Willem, Chtholly and Seniorious(珂朵莉树)
中文题面 珂朵莉树的板子--这篇文章很不错 据说还有奈芙莲树和瑟尼欧里斯树-- 等联赛考完去学一下(逃 1 //minamoto 2 #include<bits/stdc++.h> 3 # ...
- codeforces 915 E 896 C 珂朵莉树
珂朵莉树(Chtholly Tree),一种基于std::set的暴力数据结构,是由某毒瘤在2017年的一场CF比赛中提出的数据结构,原名老司机树(Old Driver Tree,ODT).由于第一个 ...
- 浅谈珂朵莉树(Chtholly Tree)——暴力而玄学的数据结构
关于它很珂学的名字- 珂朵莉树(Chtholly Tree),又称老司机树(Old Driver Tree),起源于CodeFoeces平台上编号为896C的一道题-- " Willem, ...
- 珂朵莉树(永远喜欢珂朵莉/doge)
目录 前言 可能用到前置知识 背景 构建珂朵莉树 核心函数 珂朵莉树在实际题目使用 对珂朵莉树的一些感想 最后的最后 前言 最近刚刚学内容大概是借鉴的吧,感觉这个数据结构不仅简单,还很强,有着非常柯学 ...
- CodeForces - 897E Willem, Chtholly and Seniorious(珂朵莉树)
题目链接:点击查看 题目大意:给出一个长度为 nnn 的数列,现在需要执行 mmm 次操作,每次操作分为下列四种情况: 1lrx1 \ l \ r \ x1 l r x:[l,r][l,r][l,r] ...
- [转]我的数据结构不可能这么可爱!——珂朵莉树(ODT)详解
参考资料: Chtholly Tree (珂朵莉树) (应某毒瘤要求,删除链接,需要者自行去Bilibili搜索) 毒瘤数据结构之珂朵莉树 在全是珂学家的珂谷,你却不知道珂朵莉树?来跟诗乃一起学习珂朵 ...
- CF915E Physical Education Lessons(珂朵莉树)
中文题面 据说正解是动态开点线段树而且标记也不难下传的样子 然而这种区间推平的题目还是喜欢写珂朵莉树啊--码量小-- 虽然真要构造的话随便卡-- 1 //minamoto 2 #include< ...
- 算法自学__珂朵莉树
参考资料: https://zhuanlan.zhihu.com/p/106353082 https://blog.csdn.net/CC_dsm/article/details/98166835 珂 ...
- 一种黑科技:珂朵莉树
首先要明白的是:珂朵莉树(ODT)是一种用来骗分的暴力数据结构. 珂朵莉树的思想是利用集合set,把相同且连续的元素合并为一个个区间,从而进行区间修改:因此,珂朵莉树是区间的集合,这点可以通过定义结构 ...
最新文章
- Selenium 2.0的由来及设计架构(三)
- Maltego发布新版本4.2.18
- ngrok布置外网访问环境
- 设计模式之Builder模式 (C++实现)
- java代码执行linux命令_怎么用java代码运行linux命令
- WPF XMAL获取元素的父元素,子元素
- amos调节变量怎么画_结构方程模型建模思路及Amos操作--调节变量效果确定(二)...
- GitHub客户端使用
- serialVersionUID 问题处理
- MongoDB官网下载和安装(ZIP安装)
- DDCTF2018-黑盒破解 详细WP
- 【LeetCode】274. H指数
- Git:不同仓库之间的cherry-pick
- [转贴] 扫盲转贴:Rootkit技术发展史
- 【SSD】自动化测试框架
- 计算机视觉博士去向,为什么现在不看好 CV 方向了呢?
- 爬虫:一种打破3000套限制爬取所有链家二手房源的方法
- 查看kafka的topic清单以及topic的内容
- mysql数据库errorCode 1045, state 28000
- lcd12864使用c语言pic单片机,PIC单片机+LCD12864显示汉字程序