P9481 [NOI2023] 贸易

发布时间 2023-08-01 14:10:50作者: jimmyywang

不好评价题。

容易知道在该题目条件下 \(dis[u\to v]=dis[u\to\text{LCA}(u,v)]+dis[\text{LCA}(u,v)\to v]\)。其中 \(dis[u\to\text{LCA}(u,v)]\)\(u\) 一直往父亲跳,容易预处理。现在难点在于处理出所有 \(dis[\text{LCA}(u,v)\to v]\)。换言之,是处理出所有 \(dis[u \to v]\),其中 \(v\in subtree_u\)

有很多做法,这里写两种。

做法 1:

所有满足 \(u\)\(v\) 的祖先的 \((u,v)\) 点对数量(即要处理的点对数)为 \(\sum_{i=0}^{n-1}2^i\times(2^{n-i+1}-1)=O(n2^n)\)

考虑 \(u\to v\) 的最段路长什么样。一定是 \(u\) 先向上走(也可以不走)到一个祖先 \(anc_u\),然后由 \(anc_u\) 经过一条第二类边向下走,然后经过一些不知道什么路径到达 \(v\)。其实就是 不经过 \(anc_u\) 的祖先走一条到 \(v\) 的最短路

由此,我们可以预处理出 \(d[u][v] (u\in anc_v)\) 表示从 \(u\) 开始 不经过 \(u\) 的祖先到 \(v\) 的最短路。易得此时经过的点全都是 \(u\) 子树内的点,直接从 \(u\) 开始向子树内跑一遍单源最短路,限制一下不能走 \(u\to fa_u\) 的边就行了。总复杂度 \(O(n2^n\log2^n)=O(n^22^n)\)

然后考虑用 \(d[u][v]\) 处理出 \(dis[u][v]\)。我们按深度从小到大枚举 \(u\) 并用 \(u\) 的祖先更新每个 \(dis[u][v]\)。相当于枚举 \((u,v)\) 后再枚举可能的 \(anc_u\),用 \(d[anc_u][v]\)\(dis[u\to anc_u]\)(后者之前预处理过了)来更新。


做法 2:

枚举每条第二类边,更新其影响。

观察到一条 \((u,v)\) 的第二类边只会影响 \(1\to v\) 这条链上的点对(\(v\) 子树中的点可以直接向上走),直接 \(O(n^2)\) 暴力枚举并更新。

但是如果这样做的话有些点对的更新存在疏漏。观察到 \(u\) 深度越浅,其影响的点数越多,故应该按照 \(u\) 的深度从浅到深更新。

复杂度 \(O(mn^2)\),若视 \(O(m)=O(2^n)\) 则为 \(O(n^22^n)\)


至此处理完所需的东西,而统计答案则是简单的。枚举 \(\text{LCA}\)\(u\)\(v\) 一定在两棵不同子树中。对每条路径计算它对答案贡献了多少次,加起来即可。