[模板] 树链剖分(轻重链剖分)
一些定义
- 重儿子:
结点所有儿子里子树规模最大的结点,即\(sz[ x ]\) 最大。
我第一次接触这个概念居然不是在这,而是在这。
有时间再写题解吧,这是一个不错的思维题。
- 重链:
从重儿子一直延伸到叶子结点的路径。
- 树链:
任意两点间的距离 ( 不严谨的说。
原理:
通过有序的 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;
}
最后用线段树维护区间和即可。