dfs 序七个经典问题

· · 算法·理论

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

# 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. \text{lca} \to root$ 上所有点权和 $\times -1
  2. fa(\text{lca}) \to root$ 上所有点权和 $\times -1

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

修改节点 u 权值,当且仅当 vu 的子孙节点时,uv 的值有贡献。

差分前缀和,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 的子树权值,当且仅当 vu 的子孙节点时(或 u = v),uv 的值有贡献。

$$ w_u \times (dep_v - dep_u + 1) = w_u \times dep_v - w_u \times (1 - dep_u) $$ 同问题三。