推荐博文:点分治入门
理解:
首先要找出树中的重心。
那么是什么树的重心呢?
树的重心即
依次以每个节点为根,求出他们的最大子树的节点数,根节点中最大子树节点数最小的就是树的重心。
比如以这颗树为例中:
在以1节点为根节点时,它的子树分别为两个蓝色圈所包围的部分,左边部分的节点数为3,,右边部分的节点数为2,所以他的最大子树节点数为3。
在以2为根节点,求他的最大子树,如图,最大子树的节点数为3。
这样依次求3、4、5、6的最大子树节点数。
3的最大子树节点数为4;
4的最大子树节点数为4;
5的最大子树节点数为4;
6的最大子树节点数为5;
由以上结果可知1节点和2节点的最大子树节点数最小,所以可以选择以1或者2为树的重心。
为什么要求树的重心呢?
因为如果以树的重心为根节点,从根节点出发,遍历树的其他节点,递归的层数最少。这样可以降到复杂度。
树的重心求出来之后,就可以求树的重心到其他点的距离;
还是这个图(树的重心为1),假设你要求3到6的距离(上面红线已标出),之前你已经求出树的重心到其他各点的距离了(保存在dis数组),
那么你直接求dis[3]+dis[6]即可。
哎,到这里,有同学可能就要问了。那我如果要求3到4的距离岂不是dis[3]+dis[4]=4,距离为4了,但图中3到4的距离是为2的。这不是错了吗。。
莫慌!!(以下是我的理解,如果有错误请指出)
点分治算法,在求出树的重心后,是分别对子树处理的。
以上为啥求出距离是4而不是2呢,是因为这两个点属于同一个子树,在算距离的时候,把1->2这条边的距离也算上去了,并且算了两遍,所以得出来的结果就是4;这时就要把这条边减去。
这个是前面推荐博文的代码,第89行代码函数调用就是求出树的重心到其余各点的距离,第94行代码传入的距离不是0而是e[i].z,就是要在处理子树时,把1->2这条边算进去。然后用总的得出来的结果减去子树得出来的结果。(这里的代码可能解释不太清楚)
也可以这样理解,
在以1为树的重心求出到其余各点的距离时,会在分别处理它的子树,即左右两个红圈所包围的。例如处理1节点的子树时,会把1->2距离加到子树上去,本来在处理左边子树时,2->3的距离为1,但加上1->2的距离后就变为2;这样就可以把前面重复的边去掉了。
在处理完以1节点为根的树之后,在进行分治;即第98行代码,在把两个子树重新当做一棵全新的树,求他们的重心,在重复上面的步骤。