dfs 序七个经典问题

转载——dfs 序七个经典问题

\(\LaTeX\) 美化。

dfs 序七个经典问题

点修改,子树和查询

在 dfs 序中,子树处于一个连续区间中。所以这题可以转化为:点修改,区间查询。树状数组 or 线段树即可。

树链修改,单点查询

将一条树链 \(u, v\) 上的所有点的权值加 \(w\)。这个问题可以等价为:

  1. \(u\) 到根节点的链上所有节点权值 $ + w$。
  2. \(v\) 到根节点的链上所有节点权值 \(+w\)
  3. \(\text{lca}(u, v)\) 到根节点的链上所有节点权值 \(-w\)
  4. \(fa(\text{lca}(u, v))\) 到根节点的链上所有节点权值 \(-w\)

上面四个操作可以归结为:节点 \(u\) 到根节点链上所有节点的权值 \(-w\)。修改 \(u\) 的权值,当且仅当 \(v\)\(u\) 的祖先节点时,\(u\)\(v\) 的值有贡献。

所以节点 \(u\) 的权值可以转化为节点 \(v\) 的子树节点贡献和。从贡献和的角度想:这就是点修改,区间查询问题。

修改树链 \(u, v\) 等价于 \(in_u + w, in_v + w, in_\text{lca} - w, in_{fa(\text{lca})} - w\)

查询:\(sum_{out_u} - sum_{in_u - 1}\)

用树状数组或线段树即可。

树链修改,子树和查询

树链修改部分同上一问题。下面考虑子树和查询问题:前一问是从贡献的角度,子树和同理。

对于节点 \(v\) 其到根节点的权值和,考虑其子节点 \(u\) 的贡献:\(w_u \times (dep_u - dep_v + 1) = w_u \times(dep_u + 1) - w_u \times dep_v\)

所以节点 \(v\) 的子树和为:

\[\sum_{i = in_v}^{out_v} w_i \times (dep_i + 1) - dep_v \times \sum_{i = in_v}^{out_v} w_i \]

所以用两个树状数组或线段树即可。

第一个维护 \(\sum w_i\times(dep_i+1)\)

第二个维护 \(\sum w_i\)

单点更新,树链和查询

官方做法

树链和查询与树链修改类似,树链和 \(u, v\) 等于下面四个部分和相加:

  1. \(u \to root\) 上所有点权和
  2. \(v \to root\) 上所有点权和
  3. \(\text{lca} \to root\) 上所有点权和 \(\times -1\)
  4. \(fa(\text{lca}) \to root\) 上所有点权和 \(\times -1\)

所以问题转化为:查询点 \(u \to root\) 上所有点权和。

修改节点 \(u\) 权值,当且仅当 \(v\)\(u\) 的子孙节点时,\(u\)\(v\) 的值有贡献。

差分前缀和,\(v\) 的权值 \(=\) dfs 中,\([1, in_v]\) 的区间和。

单点修改:\(in_u + w, ~ out_u + 1 - w\)

欧拉序做法

同官方做法,将 \(u, v\) 链分成 \(4\) 个部分,使用欧拉序存 dfs 序,即出入都花时间。

单点修改 \(u\) 时,将 \(in_u + w, ~ out_u - w\),这样可以做到,任意节点 \(v \to root\) 上,旁边的子树和都已经与自己抵消,所以 \(\text{dfn} \to sum[root, in_v]\) 即为答案。

子树修改,单点查询

修改节点 \(u\) 的子树权值,在 dfs 序上就是区间修改,单点权值查询就是单点查询。

区间修改,单点查询问题,用树状数组或线段树即可。

子树修改,子树和查询

用树状数组或线段树即可。

子树修改,熟练查询

树链查询同上,等价为根节点到 \(v\) 节点的链上所有节点和问题。

修改节点 \(u\) 的子树权值,当且仅当 \(v\)\(u\) 的子孙节点时(或 \(u = v\)),\(u\)\(v\) 的值有贡献。

\(u\) 对根节点到 \(v\) 节点的链上所有节点和的贡献为:

\[w_u \times (dep_v - dep_u + 1) = w_u \times dep_v - w_u \times (1 - dep_u) \]

同问题三。

posted @ 2024-08-12 21:13  Mason123456  阅读(42)  评论(0)    收藏  举报