【NOIP2014提高组】联合权值

https://www.luogu.org/problem/show?pid=1351

既然是一棵树,就先转化成有根树。有根树上距离为2的点对,路径可能长下面这样:

枚举路径上的中间点X。

 

第一种情况

对于点X(X的儿子数≥2),它的每一个儿子i与其他的儿子对权值和的贡献为Wi*(sum-Wi),则这个点所有儿子之间对权值和的贡献为:∑Wi*(sum-Wi),其中sum为点X所有儿子的权值之和。(貌似还有更高效的算法?)

对于点X (X的儿子数≥2),它的所有儿子之间可以产生的联合权值的最大值,肯定为所有儿子里面权值最大的×权值第二大的。贪心即可。

第二种情况

对于点X(除根节点和叶子节点),它的父亲与它的所有儿子之间对权值和的总贡献为:2*Wfather*sum,其中sum为点X所有儿子的权值之和。因为要求的是有序点对,所以要乘2。

对于点X(除根节点和叶子节点),它的父亲与它的所有儿子之间产生的联合权值的最大值,肯定为它的儿子里面权值最大的乘以它的父亲的权值。贪心即可。

实际代码时发现不用特意转化为有根树,只需要一遍深搜。

对于每个点,判断它的儿子数时,如果不是根则等于这个点的度数-1,如果是根则等于这个点的度数。

统计每个点对权值和的贡献,并维护最大权值。

#include <iostream>
#include <vector>
#define maxn 200005
typedef long long llint;
using namespace std;
const llint inf = 0x7fffffffffffffffll, c = 10007;
int n;
vector<int> t[maxn];
llint weight[maxn];
llint tot = 0;
llint maxlink = -inf;
void dfs(int k, int fa)
{
    llint sum = 0;
    llint maxson[2] = {-inf, -inf};
    for (int i = 0; i < t[k].size(); i++)
    {
        if (t[k][i] != fa)
        {
            sum = (sum + weight[t[k][i]]) % c;
            if (weight[t[k][i]] > maxson[0])
            {
                maxson[1] = maxson[0];
                maxson[0] = weight[t[k][i]];
            }
            else if (weight[t[k][i]] > maxson[1])
            {
                maxson[1] = weight[t[k][i]];
            }
            dfs(t[k][i], k);
        }
    }
    if (t[k].size() >= 2 + (fa != 0 ? 1 : 0))
    {
        for (int i = 0; i < t[k].size(); i++)
            if (t[k][i] != fa)
                tot = (tot + (sum - weight[t[k][i]] + c) % c * weight[t[k][i]] % c) % c;
        // tot = tot + (sum - weight[t[k][i]]) * weight[t[k][i]]
        maxlink = max(maxlink, maxson[0] * maxson[1]);
    }
    if (fa != 0 && t[k].size() >= 2)
    {
        tot = (tot + 2 * weight[fa] % c * sum % c) % c;
        maxlink = max(maxlink, maxson[0] * weight[fa]);
    }
}
int main()
{
    int a, b;
    cin >> n;
    for (int i = 1; i < n; i++)
    {
        cin >> a >> b;
        t[a].push_back(b);
        t[b].push_back(a);
    }
    for (int i = 1; i <= n; i++)
    {
        cin >> weight[i];
    }
    dfs(1, 0);
    cout << maxlink << ' ' << tot << endl;
    return 0;
}
原文地址:https://www.cnblogs.com/ssttkkl/p/7528792.html