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

点分治

时间:2020-01-22 22:11:55      阅读:85      评论:0      收藏:0      [点我收藏+]

标签:code   math   sort   大小   alc   line   continue   n+1   容斥   

点分治用来处理树上路径问题,每一次将树分治为几棵子树,然后继续递归,得到答案

每次分治时,子树的根选取为其的重心,递归的子树大小不会超过原树大小的一半,保证了时间复杂度为\(O(n\ log\ n)\)

利用容斥原理统计答案

树上有多少对点,满足两点间的距离小于等于\(k\)

\(code:\)

void dfs_root(int x,int fa)
{
    siz[x]=1,ma[x]=0;
    for(int i=head[x];i;i=e[i].nxt)
    {
        int y=e[i].to;
        if(vis[y]||y==fa) continue;
        dfs_root(y,x);
        siz[x]+=siz[y];
        ma[x]=max(ma[x],siz[y]);
    }
    ma[x]=max(ma[x],tot-siz[x]);
    if(ma[x]<ma[root]) root=x;
}
void dfs_dis(int x,int fa)
{
    len[++len_cnt]=dis[x];
    for(int i=head[x];i;i=e[i].nxt)
    {
        int y=e[i].to,v=e[i].v;
        if(vis[y]||y==fa) continue;
        dis[y]=dis[x]+v;
        dfs_dis(y,x);
    }
}
int calc(int x,int lenth)
{
    len_cnt=0;
    dis[x]=lenth;
    dfs_dis(x,0);
    sort(len+1,len+len_cnt+1);
    int sum=0,l=1,r=len_cnt;
    while(l<r)
    {
        if(len[l]+len[r]<=k) sum+=r-l,l++;
        else r--;
    }
    return sum;
}
void solve(int x)
{
    vis[x]=true;
    ans+=calc(x,0);
    for(int i=head[x];i;i=e[i].nxt)
    {
        int y=e[i].to,v=e[i].v;
        if(vis[y]) continue;
        ans-=calc(y,v);
        root=0,tot=siz[x];
        dfs_root(y,0);
        solve(root);
    }
}

点分治

标签:code   math   sort   大小   alc   line   continue   n+1   容斥   

原文地址:https://www.cnblogs.com/lhm-/p/12229531.html

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