点分治总结

【介绍】
由于树具有一般的图没有的特点,所以在竞赛中的应用更广。
在一些树上路径问题中,暴力求解时间复杂度过高,往往需要一些更为高效的算法,点分治就是其中之一。

【流程】
首先选取一个点,把无根树变成有根树。
我们可以用树型DP选点。
因为树是递归定义的,所以我们当然希望递归的层数最小。
每次选取的“重心”,(就是相连的结点数最多的连通块的结点数最小的点)

void getrot(int x,int fa)
{
    f_son[x]=1; f[x]=0;//f数组表示当x为根是,以x的子节点为根的最大子树的大小,f_son数组表示以x为根的树的大小
    for (int j=lnk[x]; j; j=nxt[j])
     if (!vis[son[j]]&&son[j]!=fa)
      {
        getrot(son[j],x);
        f_son[x]+=f_son[son[j]];
        f[x]=max(f[x],f_son[son[j]]);
      }
    f[x]=max(f[x],nn-f_son[x]);//考虑以x的父节点为根的子树的大小。
    if (f[x]<f[rot]) rot=x;//修正当前的根rot。
}

【核心代码】

void solve(int x)
{
    vis[x]=1;
    for (int j=lnk[x]; j; j=nxt[j])
     if (!vis[son[j]])
      {
        nn=f_son[son[j]]; rot=0;
        getrot(son[j],0);//接着遍历子树。
        solve(rot);
      }
}

int main()
{
    memset(vis,0,sizeof(vis));
    memset(lnk,0,sizeof(lnk));
    tot=rot=0;  nn=n;  f[0]=INF;  
    getrot(1,0);//找根
    solve(rot);//点分
    printf("%d\n",ans);
    n=read_(); m=read_();
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值