<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>可持久化 on Zirnc's Blog</title><link>https://blog.chungzh.cn/blog/%E5%8F%AF%E6%8C%81%E4%B9%85%E5%8C%96/</link><description>Recent content in 可持久化 on Zirnc's Blog</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><lastBuildDate>Sun, 14 Aug 2022 00:00:00 +0000</lastBuildDate><atom:link href="https://blog.chungzh.cn/blog/%E5%8F%AF%E6%8C%81%E4%B9%85%E5%8C%96/index.xml" rel="self" type="application/rss+xml"/><item><title>可持久化线段树笔记</title><link>https://blog.chungzh.cn/oi-history/persistent-seg-tree/</link><pubDate>Sun, 14 Aug 2022 00:00:00 +0000</pubDate><guid>https://blog.chungzh.cn/oi-history/persistent-seg-tree/</guid><description>动态开点线段树 常规写法的线段树只能维护不算很长的数组，由于空间不够，对于 $10^9$ 级别的数组却不能很好地维护。所以，我们要用到动态开点线段树。
核心思想：节点只有在有需要的时候才被创建。
比如说，要求在一个长度为 $n &amp;lt; 10^9$ 的数组上实现区间求和、单点修改的操作，初始数组元素值均为 0。
那么，我们一开始只创建一个根结点，接下来遵循动态开点的核心思想进行操作。
比如下面这张图的例子，我们依次修改 1, 2, 8 三个结点，途中创建了必要的结点。而在图中没有显示的空结点并没有被创建，视为 0，这样就节省了空间。
那么对于区间修改时，会有 pushdown() 操作，可能会修改一个不存在的结点。这时有两个解决方案：
在 pushdown() 时，如果缺少孩子，就直接创建一个新的孩子就可以了。 使用 标记永久化 技巧（李超线段树），让结点不再进行 pushdown()，进一步节省了空间。 复杂度分析：单次操作的时间复杂度是不变的，为 $O(\log n)$。对于空间复杂度，由于每次操作都有可能创建并访问全新的一系列结点，因此 $m$ 次操作的空间复杂度是 $O(m\log n)$，不再是原本线段树的 $O(n)$。
代码实现：
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 int n, cnt, root; // cnt 表示当前结点个数 int sum[N*2], ls[N*2], rs[N*2]; void upd(int&amp;amp; rt, int l, int r, int p, int f) { // 注意这里传入一个引用，可以修改 ls 或 rs 数组 if (!</description></item></channel></rss>