标签:eve lap 超过 路径 src 计数 get head closed
点分治是树上分治的一种(树上分治还有边分治),常用于解决和树上路径有关的问题。
因为树上路径有一条性质:树上的任何路径,要么经过根节点$rt$要么就全部在$rt$的一颗子树上。
正确性显而易见:树上两点的路径是唯一的,如果两点在$rt$的同一子树上,则路径完全在一颗子树上,如果在$rt$的不同子树,则必然经过$rt$。
有了这条性质,我们就可以对树上的路径进行分治:先将经过$rt$的路径处理完,此时$rt$的各个子树上的路径就互不影响了,故可以递归分治。
但怎么使得分治均匀呢?如果随意选择根节点,则如果树退化成链,则递归层数为$N$,且每次操作的节点数目都会非常多。
所以此时,我们选择树的重心,这样可以使每一次分治后剩下的最大子树的大小下降最快(重心的最大子树最小),每一次分治我们都找重心,操作本身复杂度为$O(NlogN)$,可以使分治底层执行次数降到$O(NlogN)$(主定理)。通常情况下,节点的子树超过$2$棵,则复杂度往往会低于$O(NlogN)$
void getrt(int x,int fa){ siz[x]=1; maxs[x]=0; for(int i=head[x];i;i=nxt[i]){ if(fa==to[i]&&vis[to[i]]) continue; getrt(to[i],x); siz[x]+=siz[to[i]]; maxs[x]=max(maxs[x],siz[to[i]]); } maxs[x]=max(maxs[x],sum-siz[x]); if(maxs[x]<maxs[rt]) rt=x; }
这有什么用呢?
举个例子,如果我们要统计一棵树内各个长度的路径的个数,就可以用点分治来做。
首先,我们将树的重心设为根,求出树上各点到根的距离($O(N)$),并统计每个长度的路径的数量($O(N^2)$),然后枚举每一个子树,递归执行同样的操作,并在同一个数组上统计数量
标签:eve lap 超过 路径 src 计数 get head closed
原文地址:https://www.cnblogs.com/guoshaoyang/p/10994997.html