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

树链剖分

时间:2018-07-29 21:10:36      阅读:128      评论:0      收藏:0      [点我收藏+]

标签:子节点   区间修改   return   top   void   style   节点   选择   ++   

复杂度nlog2n

边权可以转化成点权 搞一个根 把边权给到边两端深度大的哪个点 这样处理要删一个点 要删的是lca(x,y)

第一步

处理出fa deep size son

void dfs1(int u,int fa,int depth)    //当前节点、父节点、层次深度
{
    f[u]=fa;
    d[u]=depth;
    size[u]=1;    //这个点本身size=1
    for(int i=head[u];i;i=e[i].next)
    {
        int v=e[i].to;
        if(v==fa)
            continue;
        dfs1(v,u,depth+1);    //层次深度+1
        size[u]+=size[v];    //子节点的size已被处理,用它来更新父节点的size
        if(size[v]>size[son[u]])
            son[u]=v;    //选取size最大的作为重儿子
    }
}
//进入
dfs1(root,0,1);

第二步

连接重链 处理出top dfn rk 注意先处理重链再处理轻链 保证了重链的dfn值连续

void dfs2(int u,int t)    //当前节点、重链顶端
{
    top[u]=t;
    id[u]=++cnt;    //标记dfs序
    rk[cnt]=u;    //序号cnt对应节点u
    if(!son[u])
        return;
    dfs2(son[u],t);
/*我们选择优先进入重儿子来保证一条重链上各个节点dfs序连续,
一个点和它的重儿子处于同一条重链,所以重儿子所在重链的顶端还是t*/
    for(int i=head[u];i;i=e[i].next)
    {
        int v=e[i].to;
        if(v!=son[u]&&v!=f[u])
            dfs2(v,v);    //一个点位于轻链底端,那么它的top必然是它本身
    }
}

求lca步骤:

如果两个是在一个重链上的(top相同) 直接选深度小的哪个为lca

否则的话每次选两个节点中top深度深的哪个节点跳

修改步骤:

如果和lca有关的话因为dfn是连续的 就相当于在跳的过程中的每个区间都区间修改区间查询 复杂度是log2n

如果是和子树有关的话 就只是和dfs序有关了 也是区间修改区间查询

树链剖分

标签:子节点   区间修改   return   top   void   style   节点   选择   ++   

原文地址:https://www.cnblogs.com/Aragaki/p/9387548.html

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