洛谷P3787 冰精冻西瓜 题解

题意:

给定一棵 $ n $ 个节点的树,边权为 $ w $ ,表示从点 $ u $ 到点 $ v $ 所改变的值的倍数,每个点的点权初始都为 $ 0 $ 。

给定 $ q $ 次操作:

  1. 增加节点 $ i $ 及其所有子树上节点的值

  2. 查询节点 $ i $ 的点权

思路:

  • 边权均不为 $ 0 $ 的情况:

首先,从根节点开始跑 $ dfs $ ,将整棵树维护成 $ dfs $ 序,并维护每个节点 $ i $ 从其根节点到其本身的边权前缀积 $ pre[i] $ $ ( 根节点的前缀积初始化为 $ 1 $ ) $ 。

对于操作 $ 1 $ ,如果使用 $ for $ 循环遍历 $ dfs $ 序中节点 $ i $ 及其所有子树上节点 $ j $ ,那么节点 $ i $ 的点权 $ val[i] = val[i] + (x / pre[i] * pre[i]) $ ,节点 $ j $ 的点权 $ val[j] = val[j] + (x / pre[i] * pre[j]) $ 。

观察,容易发现,节点 $ i $ 及其所有子树上节点 $ j $ 的边权前缀积乘了一个相同量 $ x / pre[i] $ 。 那么,我们可以使用线段树维护区间 $ [dfn_i, dfn_i + size_i] $ ,令$ val[j] = val[j] + x / pre[i] $ $ \space (dfn_i \space \le \space j \space \le \space dfn_i + size_i) $ 。

对于操作 $ 2 $ , $ val[i] * pre[i] $ 即为最终答案。

  • 边权有 $ 0 $ 的情况:

如果一条边 $ u $ -> $ v $ ,边权 $ w = 0 $ ,那么节点 $ v $ 的前缀积 $ pre[v] = 0 $ ,节点 $ v $ 的所有子树上节点 $ j $ 的前缀积 $ pre[j] = 0 $ 。如果增加节点 $ v $ 及其所有子树上节点 $ j $ 的值,节点 $ v $ 及其子树上节点 $ j $ 的前缀积乘了一个相同量 $ x / k_v $ ,由于 $ k_v = 0 $ ,会导致“除 $ 0 $ 错误”。增加节点 $ v $ 的任意一个子树上任意一个节点 $ j $ 及节点 $ j $ 所有子树上节点 $ l $ 的值同理。

因此,我们将所有边权 $ w = 0 $ 的边删掉,将初始的整棵树变为若干棵树,从每棵树的根节点开始跑 $ dfs $ ,将每棵树维护成 $ dfs $ 序,并维护每个节点 $ i $ 从其根节点到其本身的边权前缀积 $ pre[i] $ (每个根节点的前缀积初始化为 $ 1 $ )。

参考“边权均不为 $ 0 $ ”的过程,使用线段树维护即可。

posted @ 2023-11-29 17:53  ShawyYum  阅读(51)  评论(0)    收藏  举报