浅谈树的重心

浅谈树的直径


定义:

  树上一节点最大子树的节点数最小;

性质:

  1.删除重心后所得的所有子树,节点数不超过原树的1/2,一棵树最多有两个重心;

  2.树中所有节点到重心的距离之和最小,如果有两个重心,那么他们距离之和相等;

  3.两个树通过一条边合并,新的重心在原树两个重心的路径上;

  4.树删除或添加一个叶子节点,重心最多只移动一条边;

求解:

  求解方法多种多样,分别用到不同的定义和性质:

  1.定义求解:

  siz [ i ]表示 i 节点的子树大小 dp [ i ]表示以 i 为根节点的最大子树大小,val[ i ]为i节点的点权,代码通俗易懂不过多解释了

  

inline void dfs(int now,int fa)
{
    siz[now]=val[now];
    dp[now]=0;
    for(int i=head[now];i;i=a[i].nxt)
    {
        int t=a[i].to;
        if(t==fa) continue;
        dfs(t,now);
        siz[now]+=siz[t];
        dp[now]=max(dp[now],siz[t]);
    }
    dp[now]=max(dp[now],n-dp[now]);
    if(dp[now]<dp[ans]) ans=now;
}

  2.性质求解:

  一般来说定义求解就够用了,但在某些时候性质求解更方便实用;

  根据性质2:我们可以处理出所有节点到某一节点的距离,取最小值;

  怎么求出每个节点到某一节点的距离呢?在dfs过程中向下处理是很容易的,所以我们可以先处理出所有节点到根节点的距离qwq ;

扫描二维码关注公众号,回复: 6885176 查看本文章

  siz [ i ]同上,f [ i ] 表示节点 i 的所有子节点到 i 的距离和,val[ i ] 同上, a [ i ].val 为边权,设定1 号节点为根节点;

  

inline void dfs1(int now,int fa,int deep)
{
    siz[now]=val[now];
    dep[now]=deep;
    for(int i=head[now];i;i=a[i].nxt)
    {
        int t=a[i].to;
        if(t==fa) continue;
        dfs1(t,now,deep+a[i].val);
        siz[now]+=siz[t];
        f[now]+=f[t]+siz[t]*a[i].val;
    }
}

  对于f数组的处理的理解:t的所有子节点到t的距离+now的当前子树所有节点到now的距离。

  这样就求得了根节点的距离和,我们再通过根节点递推其他节点的距离和,有如下公示:

  f [ now ] = f [ fa ] +( siz [ 根节点 ] - 2 * siz [ now ])* 边权;(now!= 根节点)

  理解如下:

  对于now的子节点,每个节点的距离减少了一个边权,总距离减少 siz [ now ] * 边权 ,对于非v子节点,每个节点距离增加了一个边权,总距离增加(siz[ 根 ]-siz [ now ])*边权

  

inline void dfs2(int now,int fa)
{
    if(now^root) f[now]=f[fa]+siz[1]-2*siz[now];
    if(f[now]<sum) res=now,sum=f[now];
    for(int i=head[now];i;i=a[i].nxt)
    {
        int t=a[i].to;
        if(t==fa) continue;
        dfs2(t,now); 
    }
}

  to be continue……

猜你喜欢

转载自www.cnblogs.com/knife-rose/p/11258403.html