推荐:博客
树分治用于解决有关路径的问题。
树分治分为点分治和边分治(其实还有一种叫“链分治”,是树的路径剖分思想的更高级的体现,一般链分治的题目都可以用路径剖分解决)。点分治就是每次找到重心,然后把重心去掉,对分成的每两棵树之间分别统计路径信息(以重心的每个相邻点为根,遍历整棵子树即可得到这个根到每个结点的统计信息),就可以知道包含这个重心的所有路径的信息,然后对于剩下的路径就是在子树里面进行同样的操作了,直到只剩一个点为止(注意这一个点所构成的路径有时也要处理一下)。边分治就是每次找到一条边,使得删掉这条边后分成的两棵子树大小尽可能平均,然后以删掉的边的两端点为根,分别统计根到两棵树中的每个结点的路径信息,最后合并算路径,即可得到包含这条边的所有路径的信息,剩下的路径在两棵树中递归处理。
下面给出几道例题
1.poj1741 Tree
点分治
题意:求树上距离小于等于K的点对有多少个。
思路:对于一棵有根树, 树中满足要求的一个数对所对应的一条路径,必然是以下两种情况之一:
1、经过根节点
2、不经过根节点,也就是说在根节点的一棵子树中
对于情况2,可以递归求解然后就变成了情况1,下面主要来考虑情况1:
从u到v的路径必然经过了顶点s,只要先求出每个顶点到s的距离再做统计即可。(注意在第一种情况中减去第二种重复计算的部分)
当树退化成链的形式时,递归的深度则退化为O(n),所以选择每次都找到树的重心作为分隔顶点。重心就是删掉此结点后得到的最大子树的顶点数最少的顶点,删除重心后得到的所有子树顶点数必然不超过n/2。
查找重心的时候,假设根为v,先在v的子树中找到一个顶点,使删除该顶点后的最大子树的顶点数最少,然后考虑删除v的情况,获得最大子树的顶点数。
两者选择最小的一个,此时选中的顶点即为重心。
递归的每一层都做了排序 O(nlogn) ,递归深度 O(logn) ,总体时间复杂度 O(nlog2n) 。
2.poj1987 Distance Statistics
买一送一 同上题
代码
3.HDU 4812 D Tree
点分治
题意:给出一棵树,让你寻找一条路径,使得路径上的点相乘mod10^6+3等于k,输出路径的两个端点,按照字典序最小输出。
思路:这类问题很容易想到树的分治,每次找出树的重心,以重心为根,将树分成若干棵子树,然后对于每棵子树再一样的操作,现在就需要求一重心为根,寻找路径,依次遍历每一个子树,然后记录子树中点到根的权值的乘积x,然后通过在哈希表中寻找
K∗逆元(x)
,看是否存在,存在则更新答案。
这里的统计必需是在时间复杂度
O(n)
以下才能过
具体细节看代码:
代码