点分治
最近学了点分治,觉得挺厉害的,准备写一下加深印象。
树上的东西都很抽象,所以自然要用抽象的东西来做,就比如点分治,点分治的思路是在当前的子树中找重心,然后用重心做事情,为什么用重心,因为重心可以使得复杂度降到log级别,然后再在这个子树里找你要的东西就行了,因为是每次都会用子树做,所以复杂度是O(nlogn)
以例题为例。
【P3806 【模板】点分治 1 】
题意:找树上距离为k的数
考虑点分治,对于每一个子树,记录它到重心的距离,然后在找距离的过程中去看每次询问的距离有没有相等的,如果有就记录下来,最后输出就好
- 找重心
根据定义直接找对于当前点所有的子树中最大的子树节点数最少的就行了。
void zzx(int x, int fa) {
sz[x] = 1, maxs[x] = 0;
// sz是当前点的儿子(包含自己)的大小,maxs是它的最大的儿子
for(int i = head[x]; i; i = e[i].nxt) {
int to = e[i].to;
if(fa == to || vis[to]) continue;
zzx(to, x);
sz[x] += sz[to];
maxs[x] = max(maxs[x], sz[to]);
}
maxs[x] = max(maxs[x], S - sz[x]);
//可能反着来他的儿子会更大,所以要加一下这个判断
if(maxs[x] < maxs[root]) root = x;
//按照定义找重心
}
别的就按题意写就行
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步