点分治总结

来源:互联网 发布:金百福软件 打不开 编辑:程序博客网 时间:2024/06/03 17:01

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

【流程】
首先选取一个点,把无根树变成有根树。
我们可以用树型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_();}
原创粉丝点击