树分治
点分治
概念
点分治是一种用于处理大规模树上路径问题的思想。
通常情况下,点分治的时间复杂度是 \(\mathcal{O}(n log n)\) 或 \(\mathcal{O}(n log^2n)\)
点分治和边分治同属树分治。通常情况下,边分治可以解决点分治所能解决的大部分问题。
淀粉质,淀粉汁
思想
以例题为引。
显然对于一棵有根树,树上的路径可以分成两类:经过根节点的路径和不经过根节点的路径。
实际上,第二种路径可以转化成第一种路径,如下图:
当对以 \(1\) 为根的子树分治时,路径 \(4, 2, 5\) 是不经过根节点的。但是当对以 \(2\) 为根的子树分治时,这条路径经过根节点。
类似地,子树改变时路径的类型也会变化。大规模子树中所有不经过根节点的路径都可以被转化成小规模子树中经过根节点的路径,并且不影响答案。
从而可以考虑对子树进行分治,借此统计所有的树上路径。
根据题目,分治一棵子树时通常需要对子树进行遍历,单次时间复杂度 \(\mathcal{O}(size)\)。考虑在对子树分治时改变子树结构,使得整棵树平衡。
选取重心作为子树的根节点即可。
时间复杂度分析:设树中节点总数为 \(n\)。易知以树的重心为根节点时,根节点的子树大小最大为 \(\frac{n}{2}\)。故而最多递归分治 \(O(log n)\) 层,
处理每层的时间复杂度约为 \(\mathcal{O}(n)\) 或 \(\mathcal{O}(n log n)\)。所以总时间复杂度为 \(\mathcal{O}(n log n)\) 或 \(\mathcal{O}(n log^2n)\)。
另,一种基于错误的寻找重心方法的点分治的复杂度分析。结论:复杂度不高于一般点分治。
错误的写法体现在求重心时一并统计子树大小,不影响复杂度,但是常数更大,且点分树树高不为严格 \(log n\)。
实际上点分治相当于钦定处理经过分治重心部分(或其子树)的贡献。
边分治
类似于点分治,不过钦定的并非经过子树重心而是一条使得子树尽量平衡的边。
注意直接边分治会被菊花图卡成 \(O(n^2)\),所以需要先进行三度化。
三度化的大概思路是对于每一条边 \((u, v, w)\),考虑新建一个虚点 \(x\),连接 \((u, x, 0), (x, v, w)\),然后 \(x\) 继承 \(u\) 的剩余边继续三度化。
经过三度化的树会变成二叉树。
点分树
概念
点分树是一种用于维护动态点分治的重构树,基于点分治构造。
当题目所求与树原本的形态无关时,可以使用点分树。
点分树单次操作的时间复杂度根据题目需求和使用的数据结构而变化,例如用树状数组维护,时间复杂度为 \(\mathcal{O}(log^2 n)\)
构造
点分树基于点分治构造,点分治时每次将当前子树的重心与上一层子树的重心连边即可构造点分树。
点分树的形态可能不唯一,但都可以维护动态点分治。
性质
-
树高严格小于等于 \(log_2 n\)
-
从点分树根结点到结点 \(u\) 的路径,即为点分治时从整棵树的重心分治到结点 \(u\) 所经过的子树重心。
-
点分树上,结点 \(u\) 的子树即为点分治时以结点 \(u\) 为子树重心时需要遍历的结点。
-
在点分树上从 \(u\) 开始一直向上跳,统计每个结点的子树对于 \(u\) 的贡献,实质上等价于在原树中从重心开始分治到 \(u\)(可能需要容斥)
边分树
对于每个结点均有一棵(伪)边分树(二叉树链),基于边分治构造。
是一棵二叉树。
构造
考虑边分时形成的两个连通块。
对于深度较大的连通块中所有的结点,都在其链的底部添加一个右子结点。
对于另一个连通块添加左子结点。
这里每条二叉树链的深度为 \(O(\log n)\)
对所有二叉树链进行线段树合并得到的即为边分树。
性质
-
边分树的左右子结点代表的是边分时不同的层。
-
对于两个不同的结点到根的路径,如果其中每个结点和其父结点的左右子结点关系均对应,则这两个结点一直在同一层边分。
-
树高为 \(O(\log n)\)