正题
评测记录:https://www.luogu.org/recordnew/lists?uid=52918&pid=P1351
题目大意
一棵树,每个点有权值,求两个距离为2的点使权值之积最大和所以这种点对的权值之积的和。
解题思路
分为两种情况:
1.一个点是另一个点的爷节点,这时候在遍历时保存爷节点就好了。
2.一个点是另一个点的兄弟,这时候在一个点跑儿子的时候计算就好。
code
#include<cstdio>
#include<algorithm>
#define N 200010
#define ll long long
using namespace std;
struct line{ll to,next;
}a[N*2];
ll n,x,y,maxs,ls[N],tot,w[N],ans;
void addl(ll x,ll y)
{a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;
}
void dp(ll x,ll fa1,ll fa2)//第一种情况
{ans=(ans+w[x]*w[fa2])%10007;maxs=max(maxs,w[x]*w[fa2]);for(ll i=ls[x];i;i=a[i].next){ll y=a[i].to;if(y!=fa1) dp(y,x,fa1);}
}
void dp2(ll x,ll fa)//第二种情况
{ll max1=0,max2=0,sum=0;for(ll i=ls[x];i;i=a[i].next){ll y=a[i].to;if(y!=fa){dp2(y,x);ans=(ans+sum*w[y]%10007)%10007;sum+=w[y];}if(w[y]>max1) swap(max1,max2),max1=w[y];else if(w[y]>max2) max2=w[y];}maxs=max(maxs,max1*max2);
}
int main()
{scanf("%lld",&n);for(ll i=1;i<n;i++){scanf("%lld%lld",&x,&y);addl(x,y);addl(y,x);}for(ll i=1;i<=n;i++)scanf("%lld",&w[i]);dp(1,0,0);dp2(1,0);printf("%lld %lld",maxs,ans*2%10007);
}