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

一些定义

  • 重儿子:

结点全部儿子里子树规模最大的结点,即\(sz[ x ]\) 最大。算法

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

P5666 CSP-S2019 树的重心code

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

  • 重链:

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

  • 树链:

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

原理:

经过有序的 dfs

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

两遍 dfs

\(1.\) 处理出须要的信息:时间

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

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

\(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;
}

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