[模板] 树链剖分(轻重链剖分)

一些定义

  • 重儿子:

结点所有儿子里子树规模最大的结点,即\(sz[ x ]\) 最大。

我第一次接触这个概念居然不是在这,而是在这。

P5666 CSP-S2019 树的重心

有时间再写题解吧,这是一个不错的思维题。

  • 重链:

从重儿子一直延伸到叶子结点的路径。

  • 树链:

任意两点间的距离 ( 不严谨的说。

原理:

通过有序的 dfs

先跑重儿子,回来再跑轻儿子,最后形成一个特殊的 dfs 序。

两遍 dfs

\(1.\) 处理出需要的信息:

\(de , fa , sz , top\)(所处于重链的起点编号)。

\(2.\) 跑特殊的 \(dfs\) ,形成 \(dfs\) 序。

\(dfs\) 序的性质

  • 一条链上的序是连续的。

  • 一棵子树内的 dfs 序为 \(dfn[x]\)\(dfn[x] + sz[x] + 1\),也是连续的。

树链剖分要解决的问题

给一棵子树或者一条树链上的结点全部加上一个权值。

树链剖分的主算法

利用特殊 dfs 序的性质,分几步来看:

假设现在要将树链 \((x , y)\)上的权值加上某个数。

\(1.\) 如果 \(x\)\(y\) 所处链不同,选取深度较大的结点爬到链端处,一边跑一边把路径上的结点加上权值 (感性理解)。

\(2.\) 最后肯定有一个结点跑到 \(x\)\(y\)\(lca\) 处。

\(3.\) 处理 \(LCA\) 到另外一个结点的那段就可。

inline int qRange(int x,int y){
    int ans=0;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        res=0;
        query(1,1,n,id[top[x]],id[x]);
        ans+=res;
        ans%=mod;
        x=fa[top[x]];
    }
    
    if(dep[x]>dep[y])swap(x,y);
    res=0;
    query(1,1,n,id[x],id[y]);
    ans+=res;
    return ans%mod;
}

最后用线段树维护区间和即可。

posted @ 2021-08-12 16:40  ¶凉笙  阅读(14)  评论(0编辑  收藏  举报