\(dis(i,j)\) 有两种转换方式,第一种是统计每条边被经过了多少次,第二种是变成 \(\sum_{i=l}^{r} \sum_{j=l}^{r} dep(lca(i,j))\)。这里采用第二种(因为第一种寄了)。
先考虑暴力,采取换根 DP:把 \([l,r]\) 建一棵虚树。对于一个点 \(x\) 尝试计算 \(\sum_{y} dep(lca(x,y))\)。\(y\) 分成两部分,是 \(x\) 的子孙以及不是 \(x\) 的子孙。前者是好算的。对于后者,记 \(f_{x} = \sum_{y 不是x的子孙} dep(lca(x,y))\),从上往下换根 DP 计算即可。
所以现在我们能做到:\(O((|S|+|T|) \log (|S|+|T|))\) 对于每个满足 \(i \in S\) 的 \(i\) 求出 \(\sum_{j \in T} dis_{i,j}\)。
尝试使用分块。答案有三部分(以下时间复杂度分析均不考虑排序的 \(\log\),后文有解决方法):
- 散块与散块的点:暴力即可。这部分时间复杂度为 \(O(qB)\)。\(B\) 为块长。
- 整块与整块的点:预处理 \(f_{x,y}\) 表示 \(\sum_{i \in S} \sum_{j \in T} dis_{i,j}\)。这部分时间复杂度为 \(O(\frac{n^2}{B})\)。
- 整块与散块的点。预处理 \(Pre_{v,x}\) 表示 \(\sum_{i \in [begin_{v},v]} \sum_{j \in [1,第x个块]}dep(lca(i,j))\)。其中 \(begin_{v}\) 表示 \(v\) 所属的块的起始位置。再预处理 \(Suf_{v,x}\) 表示 \(\sum_{i \in [v,end_{v}]} \sum_{j \in [1,第x个块]}dep(lca(i,j))\)。其中 \(end_{v}\) 表示 \(v\) 所属的块的起始位置。这实际上就是两个前缀和。这其实也是好算的。对同一块的 \(Suf\) 一起算,对同一块的 \(Pre\) 一起算。这部分时间复杂度应该是 \(O(\frac{n^2}{B})\)。但是会超空间,但是很明显我们不需要存下来,离线一下,算到哪给哪个询问的答案加上贡献就好了。
瓶颈在于建虚树时的排序,解决方法也很简单,给每块都先按照 dfn 排序,然后算两块之间时归并一下,排序就不带 \(\log\) 了。要用到欧拉序求 LCA。
取 \(B = \sqrt n\),时间复杂度为 \(O((n +q)\sqrt{n})\)。