题目描述
无向连通图 G 有 n 个点,n−1 条边。点从 1 到 n 依次编号,编号为 iii 的点的权值为 Wi,每条边的长度均为 1。图上两点 (u,v)的距离定义为 u 点到 v 点的最短距离。对于图 G 上的点对 (u,v),若它们的距离为 2,则它们之间会产生Wv×Wu 的联合权值。
请问图 G 上所有可产生联合权值的有序点对中,联合权值最大的是多少?所有联合权值之和是多少?
输入输出格式
输入格式:
第一行包含 1 个整数 n。
接下来 n−1 行,每行包含 2 个用空格隔开的正整数 u,v,表示编号为 u 和编号为 v 的点之间有边相连。
最后 1 行,包含 n 个正整数,每两个正整数之间用一个空格隔开,其中第 i 个整数表示图 G上编号为 i 的点的权值为 Wi。
输出格式:
输出共 1 行,包含 2 个整数,之间用一个空格隔开,依次为图 G 上联合权值的最大值和所有联合权值之和。由于所有联合权值之和可能很大,输出它时要对10007取余。
输入输出样例
输入样例#1:
5
1 2
2 3
3 4
4 5
1 5 2 3 10
输出样例#1:
20 74
解释:很明显在树上进行dp,每个点维护4个值, s u m 1 [ r o o t ] , s u m 2 [ r o o t ] , M a x 1 [ r o o t ] , M a x 2 [ r o o t ] sum1[root],sum2[root],Max1[root],Max2[root] sum1[root],sum2[root],Max1[root],Max2[root],分别是root孩子的权和,权平方和,最大孩子,次大孩子。那么答案就是 s u m 1 [ r o o t ] ∗ s u m 1 [ r o o t ] − s u m 2 [ r o o t ] , sum1[root]*sum1[root]-sum2[root], sum1[root]∗sum1[root]−sum2[root],和 2 ∗ s u m 1 [ s o n ] ∗ a [ r o o t ] 2*sum1[son]*a[root] 2∗sum1[son]∗a[root],孩子兄弟之间的贡献,和根节点与子孙节点的贡献,并且维护好最大值就行了,也分两种情况,同上。
#include<iostream>
#define N 200004
#define mod 10007
using namespace std;
int a[N]={0};
int head[N]={0};
int nex[2*N]={0};
int V[2*N]={0};
int tot=0;
int sum1[N]={0};
int sum2[N]={0};
int Max1[N]{0};
int Max2[N]={0};
int ans=0,ret=0;
int n=0;
void add(int x,int y){
tot++;
nex[tot]=head[x];
V[tot]=y;
head[x]=tot;
}
void DP(int x,int fa){
for(int i=head[x];i;i=nex[i]){
int to=V[i];
if(to==fa) continue;
sum1[x]+=a[to];
sum1[x]%=mod;
sum2[x]+=a[to]*a[to];
sum2[x]%=mod;
if(a[to]>Max1[x]){
Max2[x]=Max1[x];
Max1[x]=a[to];
}else if(a[to]>Max2[x]){
Max2[x]=a[to];
}
DP(to,x);
}
ret+=sum1[x]*sum1[x]-sum2[x];
ret%=mod;
ans=max(ans,Max1[x]*Max2[x]);
for(int i=head[x];i;i=nex[i]){
int to=V[i];
if(to==fa) continue;
ret+=2*sum1[to]*a[x];
ret%=mod;
ans=max(ans,a[x]*Max1[to]);
}
}
int main(){
ios::sync_with_stdio(false);
cin>>n;
for(int i=0,x,y;i<n-1;i++){
cin>>x>>y;add(x,y);add(y,x);
}
for(int i=1;i<=n;i++) cin>>a[i];
DP(1,-1);
cout<<ans<<" "<<ret%mod<<endl;
return 0;
}