码迷,mamicode.com
首页 > 其他好文 > 详细

点分治

时间:2019-06-09 22:11:22      阅读:131      评论:0      收藏:0      [点我收藏+]

标签: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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!