Loading docs/misc/index.md +1 −0 Original line number Diff line number Diff line Loading @@ -20,3 +20,4 @@ - 矩阵树定理 - DSU on Tree - 朱刘算法(并不是最小生成树) - 珂朵莉树 docs/misc/odt.md 0 → 100644 +95 −0 Original line number Diff line number Diff line ## 名称简介 老司机树,ODT(Old Driver Tree),珂朵莉树(Ctholly Tree)。 起源自[CF896C](https://codeforces.com/problemset/problem/896/C)。 ## 前置知识 会用 STL 的 set 就行。 ## 核心思想 把值相同的区间合并成一个结点保存在 set 里面。 ## 用处 骗分。 只要是有区间赋值操作的数据结构题都可以用来骗分。 一般出题人不会**刻意**卡,但是不小心卡了就…… 如果要保证复杂度正确,必须保证数据随机。 证明在[此](http://codeforces.com/blog/entry/56135?#comment-398940)。 ## 正文 首先,结点的保存方式: ```cpp struct node { int l, r; mutable int v; inline bool operator(const node &o) const { return l < o.l; } }; ``` 其中, `int v` 是你自己指定的附加数据。 然后,我们定义一个 `set<node> odt;` 来维护这些结点。 为简化代码,可以 `typedef set<node>::iterator IT` 。 ### split 最核心的操作之一 `split` ,它用于取得以 $x$ 开头的结点。 参考代码如下: ```cpp IT split(int x) { if (x > n) ; return odt.end(); IT it = --odt.upper_bound((node){x, 0, 0}); if (it->l == x) return it; int l = it->l, r = it->r, v = it->v; odt.erase(it); odt.insert((node){l, x - 1, v}); return odt.insert((node){x, r, v}).first; } ``` 这个玩意有什么用呢? 任何对于 $[l,r]$ 的区间操作,都可以转换成 set 上 $[split(l),split(r + 1))$ 的操作。 ### assign 另外一个重要的操作 `assign` 用于对一段区间进行赋值。 对于 ODT 来说,区间操作只有这个比较特殊,也是保证复杂度的关键。 如果 ODT 里全是长度为 $1$ 的区间,就成了暴力,但是有了 `assign` ,可以使 ODT 的大小下降。 参考代码如下: ```cpp void assign(int l, int r, int v) { IT itr = split(r + 1), itl = split(l); odt.erase(itl, itr); odt.insert((node){l, r, v}); } ``` ### 其他操作 套模板就好了,参考代码如下: ```cpp void performance(int l, int r) { IT itr = split(r + 1), itl = split(l); for (; itl != itr; ++itl) { // Perform here } } ``` ## 习题 - [BZOJ 1858.\[SCOI2010\]序列操作](https://www.lydsy.com/JudgeOnline/problem.php?id=1858) - [BZOJ 4592.\[SHOI2015\]脑洞治疗仪](https://www.lydsy.com/JudgeOnline/problem.php?id=4592) - [洛谷 2787. 理理思维](https://www.luogu.org/problemnew/show/P2787) - [洛谷 4979. 矿洞:坍塌](https://www.luogu.org/problemnew/show/P4979) mkdocs.yml +1 −0 Original line number Diff line number Diff line Loading @@ -252,6 +252,7 @@ nav: - 读入、输出优化: misc/io.md - 离散化: misc/discrete.md - 树上启发式合并: misc/dsu-on-tree.md - 珂朵莉树: misc/odt.md # Theme theme: Loading Loading
docs/misc/index.md +1 −0 Original line number Diff line number Diff line Loading @@ -20,3 +20,4 @@ - 矩阵树定理 - DSU on Tree - 朱刘算法(并不是最小生成树) - 珂朵莉树
docs/misc/odt.md 0 → 100644 +95 −0 Original line number Diff line number Diff line ## 名称简介 老司机树,ODT(Old Driver Tree),珂朵莉树(Ctholly Tree)。 起源自[CF896C](https://codeforces.com/problemset/problem/896/C)。 ## 前置知识 会用 STL 的 set 就行。 ## 核心思想 把值相同的区间合并成一个结点保存在 set 里面。 ## 用处 骗分。 只要是有区间赋值操作的数据结构题都可以用来骗分。 一般出题人不会**刻意**卡,但是不小心卡了就…… 如果要保证复杂度正确,必须保证数据随机。 证明在[此](http://codeforces.com/blog/entry/56135?#comment-398940)。 ## 正文 首先,结点的保存方式: ```cpp struct node { int l, r; mutable int v; inline bool operator(const node &o) const { return l < o.l; } }; ``` 其中, `int v` 是你自己指定的附加数据。 然后,我们定义一个 `set<node> odt;` 来维护这些结点。 为简化代码,可以 `typedef set<node>::iterator IT` 。 ### split 最核心的操作之一 `split` ,它用于取得以 $x$ 开头的结点。 参考代码如下: ```cpp IT split(int x) { if (x > n) ; return odt.end(); IT it = --odt.upper_bound((node){x, 0, 0}); if (it->l == x) return it; int l = it->l, r = it->r, v = it->v; odt.erase(it); odt.insert((node){l, x - 1, v}); return odt.insert((node){x, r, v}).first; } ``` 这个玩意有什么用呢? 任何对于 $[l,r]$ 的区间操作,都可以转换成 set 上 $[split(l),split(r + 1))$ 的操作。 ### assign 另外一个重要的操作 `assign` 用于对一段区间进行赋值。 对于 ODT 来说,区间操作只有这个比较特殊,也是保证复杂度的关键。 如果 ODT 里全是长度为 $1$ 的区间,就成了暴力,但是有了 `assign` ,可以使 ODT 的大小下降。 参考代码如下: ```cpp void assign(int l, int r, int v) { IT itr = split(r + 1), itl = split(l); odt.erase(itl, itr); odt.insert((node){l, r, v}); } ``` ### 其他操作 套模板就好了,参考代码如下: ```cpp void performance(int l, int r) { IT itr = split(r + 1), itl = split(l); for (; itl != itr; ++itl) { // Perform here } } ``` ## 习题 - [BZOJ 1858.\[SCOI2010\]序列操作](https://www.lydsy.com/JudgeOnline/problem.php?id=1858) - [BZOJ 4592.\[SHOI2015\]脑洞治疗仪](https://www.lydsy.com/JudgeOnline/problem.php?id=4592) - [洛谷 2787. 理理思维](https://www.luogu.org/problemnew/show/P2787) - [洛谷 4979. 矿洞:坍塌](https://www.luogu.org/problemnew/show/P4979)
mkdocs.yml +1 −0 Original line number Diff line number Diff line Loading @@ -252,6 +252,7 @@ nav: - 读入、输出优化: misc/io.md - 离散化: misc/discrete.md - 树上启发式合并: misc/dsu-on-tree.md - 珂朵莉树: misc/odt.md # Theme theme: Loading