点分治
点分治 蒟蒻迟迟没法开点分治的坑,主要是因为最近找了几道点分治题,全都可以用 长链剖分 写,由于博主又懒又菜,所以点分治没有得到练习的机会。终于,最近安排了专题分享,最菜的chd捡了一个分治专题,不得不学学这些东西了。 举个简单的例子,我们对树上的路径有一些询问。我们考虑对于树上的任意一个点,它的子树中的路径可以分为两类:一种是 经过根节点的路径 ,一种是 不经过根节点的路径 。由于不经过根节点的路径可以递归处理,这样分治的思路就很明显了。对于每一个点的子树,可以选取一个点作为根节点,递归到当前层时,只处理过根节点的路径,然后递归处理我们选定的根节点的儿子,就可以考虑到所有路径。 但是需要考虑一种极端情况:假如题目给出了一条长度为 \(n\) 的链,而我们第 \(i\) 层递归选定第 \(i\) 个点作为根节点往下递归,那就要递归 \(n\) 层,总的复杂度无法保证。这时我们就要考虑选取根节点的技巧了,每次递归选取 树的重心 为根节点,由于重心有一个性质:删除重心后得到的森林中的每一棵树的大小都不超过原树的一半,这样就能保证递归层数是 \(logn\) 层。 那么怎样求重心呢?考虑树的重心定义为一棵树中删除它后能使得到的森林中最大的树最小的点。一遍dfs就能求出,具体的实现下面会有。 接下来看题吧。 P4178 Tree 做这道题之前可以先看看它的弱化版 CF161D