题意简述
一棵 $N$ 个节点的树,以 1 为根。树上的每个节点有两个权值:$v_i$,$t_i$。初始时均为 0。
$Q$ 次操作:
1 u d
$\hskip .6em$ 对 $u$ 到根上所有点的 $v_i\text{+=}d$2 u d
$\hskip .6em$ 对 $u$ 到根上所有点的 $t_i\text{+=}v_i \times d$
输出 $Q$ 次操作后所有节点的权值。
数据范围:$N,Q \leqslant 10^5$。
数据保证 64 位整数不会溢出。
题目简析
先考虑在一段区间中怎么维护这两个操作。
$t_i$ 增加值是 $v_i$ 和 $d$ 的乘积。
- 当 $v_i$ 不发生改变,可以累加 $d$ 的值, $d’=\sum d$;
- 当 $v_i$ 发生改变,$t_i
\text{+=}v_i \times d’$,$d’=0$,$v_i\text{+=}d$。
由于我们求的是 $Q$ 次操作后每个节点的 $t_i$ 值;
维护一个类似 区间更新,单点求值
的问题即可。
操作一($v_i$ 发生变化)
1 | void Pushdown(int o, int lft, int rht) { |
操作二($v_i$ 不发生变化)
1 | void Update(int o, int lft, int rht, LL add) { |
最后的 Query
操作只要把所有的标记 Pushdown
到叶子节点即可。
解决了区间的问题,剩下的只要树剖一下就好了。
复杂度分析
Update
操作是 $O(\log N)$ 的,执行 $Q$ 次;Query
操作是 $O(N)$ 的,但只执行一次。
空间复杂度
$O(N)$时间复杂度
$O(Q\log N + N)$
Hint
数据范围比较大,会爆栈,需要手动扩栈。
1 |
51nod 暂只有 Visual C++ 支持手动扩栈。
*** 树链剖分 ***