P12536 [XJTUPC 2025] 我永远喜欢希儿·芙乐艾 最优解
题意
给定一个大小为 \(n\) 的树,有 \(m\) 个树链加,然后给定 \(q\) 次操作,操作分三种,其一是执行编号 \(L\) 到 \(R\) 的树链加,其一是查询子树和,其一是换根,要求空间线性。
做法
看起来究极困难,让我们考虑一些子问题。
子问题1
区间加,区间和怎么使用树状数组做,当然使用线段树可以做到 \(\mathcal O(\log n)\),但是用树状数组做更具启发性。
你发现还是存储差分后的数组,然后每次询问就会变成 \(\sum^{r}_{i=l} (r-i+1) \times a_i\) 状物,拆一下发现 \((r+1) \times a_i\) 就是普通树状数组,\(i \times a_i\) 依旧是普通树状数组,于是做完了。
子问题2
树链加,子树和怎么做。
这个东西 \(\mathcal O(\log^2 n)\) 相当简单,但是不够优秀,树链剖分没什么优化空间。
于是你考虑在树上差分,修改时直接对这两个点上加,然后在它们的最近公共祖先与最近公共祖先的父亲处减。
查询还是把子树拍成区间,记 \(dep_i\) 表示 \(i\) 的深度,询问就变成 \(\sum^{r}_{i=l} (dep_i-dep_x+1) \times a_i\),这个东西与上个问题一样拆成两个树状数组即可做。
时间复杂度是树状数组的单 \(\log\),所以很优秀。
原问题
至此你已经会了这题 \(\mathcal O(n^2 \log n)\) 的做法,于是有超级显然的优化,对操作序列分块。
于是操作序列的整块可以用上文差分转两次树上前缀和的方式完成,第一次树上前缀和还原出树,第二次树上前缀和方便我们查询块对子树的影响。
这是块修改可以直接让标记加一,询问时每个块直接 \(\mathcal O(1)\) 查询。
对于散块,我们可以用上文的树状数组。
两相平衡,复杂度为 \(\mathcal O(n\sqrt{ n\log n})\)。
注意到整块的空间复杂度与散块的时间复杂度双双爆炸,考虑进一步优化。
整块对于每一个块逐块处理,这一步是简单的。
对于散块,树状数组能维护的东西显然也可以使用 \(\mathcal O(1) - \mathcal O(\sqrt n)\) 的 分块维护。
于是空间复杂度降到了 \(\mathcal O(n)\),时间复杂度变成了 \(\mathcal O(n \sqrt n)\)。
于是我们做完了……吗?
发现换根操作被我们遗忘了,其实换根是假的,换根对树链加完全没有影响。子树和时如果根不在子树内也不会有影响,如果查询的是根可以输出全局和,如果根在查询的子树内直接用全局和减去根所在的子树和即可,于是就真的做完了。
代码
一定要预处理树链修改的最近公共祖先,不然你就会像我一样卡常,结果一预处理直接拿到最优解。
可以使用倍增求最近公共祖先而非树剖,空间复杂度劣一点问题不大,但是得使用链式前向星。
代码调试信息太长了,不想放。

浙公网安备 33010602011771号