题解的代码实现的正确性不是很显然,拿第一篇题解举例:
inline void solve(int u,int v,int w){
++ext;
int pw,pre = w,i = v;
while(i!=fa[u]){
sum[i] = pre;
pre += b[i];
i = fa[i];
}
sum[ext] = sum[u];
sum[u] = 0;
i = v;
while(i!=fa[u]){
pw = min(sum[i],sum[ext]-sum[i]);
adj[ext].push_back(edge(i,pw));
adj[i].push_back(edge(ext,pw));
i = fa[i];
}
}
我们查询环上两个点的距离是通过算出环上两个点到环上定点距离实现的,但是我们只开了一个数组,而且一个点会在很多个环中出现。
考虑 dfs 树,我们按照 dfs 树搜,搜出来的环的终点肯定是最浅的点(按照题解的写法),然后你注意到 dfs 树上如果两个环有交,那么这个交点肯定是深度较深的环中深度最浅的点。
sum[u] = 0;
这句话比较重要,它说的是把这个环上最浅的点的这个权值设为 0,因为环上最浅的点的权值肯定是用不到的(考虑 lca,用到这个权值当且仅当两点 lca 是这个环的方点,但是环上最浅的点肯定是方点的父亲)。并且我们是由深到浅的找环,那么我们会在搜一个更浅的环时把这个点赋上另一个环中的权值。
从而,我们避免了环上的交点,因为我们发现所有环的交点都是无意义的。