[noip2014] 联合权值

传送门

讲一下题意:

有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;
}
原文地址:https://www.cnblogs.com/zcr-blog/p/11760903.html