先考虑怎么高效地找到重心。
我们从根节点(令其为 \(1\))开始,每次往一个儿子走,要求以这个儿子为中心的的距离和更小(把式子写出来,容易知道这样的儿子要么没有,要么唯一),如果没有这样的儿子就结束。发现这个东西其实跟边权没有关系,因为写出来是一个 \(c(u,v)\times(s_1-2\times s_v)\) 的形式(\(s\) 是子树点权和),我们只关注它的正负,所以和边权无关。所以走的条件就是找一个满足 \(2\times s_v\ge s_1\) 的儿子 \(v\)。
怎么做呢?相当于找到 dfs 序最大的 \(x\) 使得 \(2\times s_x \ge s_1\)。把 \(s\) 放在线段树上 dfs 序对应位置维护,一个节点维护区间 \(s\) 最大值,查询的时候直接线段树上二分即可。
找到重心后,求答案是显然的,每一条边的贡献是边权乘上子树内/外点权和,用两棵线段树维护,一棵专门维护边权乘以子树内和,另一棵维护边权乘以子树外和。相当于维护区间 \(\sum A_i\) 和 \(\sum B_i\),操作是 \(A\) 的区间加,以及求区间 \(\sum A_i\times B_i\),是很经典的。
至此我们用 \(\mathcal O(n+q\log^2 n)\) 的时间复杂度解决了本题。