思路:
对于一个根节点,他所有儿子之间的距离都为2,于是设置一个sum[x]代表所有儿子之和,然后每次递归时统计就行了
并且对于一个节点,他的父亲和儿子之间的距离也为2,用父亲的w*sum[x]就能计算这一部分的情况
至于最大值,找出儿子中次大和最大,不要忘记父亲
c o d e code code
#include<iostream>
#include<cstdio>
using namespace std;
long long mod=10007;
long long n, head[201010], tot, ans1, ans2;
long long w[201010], sum[201010];
struct node
{
long long to, next;
}b[2010101];
void add(long long x, long long y)
{
b[++tot]=(node){y, head[x]};
head[x]=tot;
}
void dfs(long long x, long long fa)
{
long long maxx=0, maxx_=0;
for(long long i=head[x]; i; i=b[i].next)
{
long long y=b[i].to;
if(y==fa)
continue;
sum[x]=sum[x]+w[y];
if(w[y]>=maxx)
{
maxx_=maxx;
maxx=w[y];
}
else if(w[y]<maxx&&w[y]>maxx_)
maxx_=w[y];
dfs(y, x);
}
ans2=max(ans2, maxx*maxx_);
if(fa!=0)
ans1=(ans1+w[fa]*(sum[x]%mod)*2)%mod, ans2=max(ans2, w[fa]*maxx);
for(long long i=head[x]; i; i=b[i].next)
{
long long y=b[i].to;
if(y==fa)
continue;
ans1=(ans1+(sum[x]-w[y])%mod*w[y]%mod)%mod;
}
}
int main()
{
scanf("%lld", &n);
for(long long i=1; i<n; i++)
{
long long x, y;
scanf("%lld%lld", &x, &y);
add(x, y), add(y, x);
}
for(long long i=1; i<=n; i++)
scanf("%lld", &w[i]);
dfs(1, 0);
printf("%lld %lld", ans2, ans1);
return 0;
}