讲一下题意:
有n个节点,n-1条边,无重边无子环(这不就是一棵树吗)。每两条边的权值为1,每个点有一个值W,对于有序点对(u, v)满足u到v之间的距离为2,就会产生一个联合权值Wu * Wv。求∑Wu* Wv 和max{Wu * Wv}。
这道题刚开始看上去很怪异,就想着求一下深度再求一下LCA然后枚举每个满足条件的点对。不过后来我发现这是一棵树,两个点之间的距离为2的话只有一种可能:
A -- B -- C
(A, C)是有序点对。
所以我们只需要枚举中转点(B),然后对于每一个中转点会产生∑
很明显,这两个值都可以通过前缀和预处理出来。
之后对于每个中转点再预处理一个最大值个一个次大值得MAX = max{最大值 * 次大值}。
#include <iostream> using namespace std; const int MOD = 10007, N = 200010; struct node{ int pre, to; }edge[2 * N]; int head[N], tot; int s1[N], s2[N], ma1[N], ma2[N]; int n, maxi, sum; int x[N], y[N], w[N]; void add(int u, int v) { //存边,预处理 edge[++tot] = node{head[u], v}; head[u] = tot; s1[u] = (s1[u] + w[v]) % MOD; s2[u] = (s2[u] + w[v] * w[v]) % MOD; if (w[v] > ma1[u]) { ma2[u] = ma1[u]; ma1[u] = w[v]; } else if (w[v] > ma2[u]) { ma2[u] = w[v]; } } int main() { cin >> n; for (int i = 1; i < n; i++) cin >> x[i] >> y[i]; for (int i = 1; i <= n; i++) cin >> w[i]; for (int i = 1; i < n; i++) add(x[i], y[i]), add(y[i], x[i]); for (int pos = 1; pos <= n; pos++) { sum = (sum + s1[pos] * s1[pos] - s2[pos]) % MOD;//注意要取模 maxi = max(maxi, ma1[pos] * ma2[pos]); } cout << maxi << " " << sum << endl; return 0; }