来自你谷的题目
**
解析
首先看一眼数据规模
【数据说明】
对于 30%的数据,1 < n ≤ 100;
对于 60%的数据,1 < n ≤ 2000;
对于 100%的数据,1 < n ≤ 200,000,0 < Wi ≤ 10,000
然后我傻叉地用了二维数组,然后不负众望地炸了,mmp
后来才知道二维最多开5000 qwq
不得已只好用数组模拟邻接表储存
至于求联合权值的最大值可以枚举每个点周围的最大和次大的点,然后比较和的话,每两个点都要乘一下,
举个栗子 s点周围有a,b,c,d,e五个点
sum+=2*[(ab+ac+ad)+(bc+bd)+cd],这时候就可以用乘法结合律了
so,其余的看代码吧
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
struct edge{
int next,to;
}a[500003];//数组模拟邻接表储存
int h[500003],num;
int n,w[200003],max_w,sum;
const int mod1=10007;//题目只要求对和取模
void deliver(int x)
{
int max1=0,max2=0,he=0;//一定要初始化!!!!
for(int j=h[x];j!=0;j=a[j].next)
{
if(w[a[j].to]>max1)
{//最大
max2=max1;
max1=w[a[j].to];
}
else if(w[a[j].to]>max2)
max2=w[a[j].to];//次大
sum=(sum+he*w[a[j].to])%mod1;//每次加入一个点都要去乘以其他所有点(运用乘法结合律)
he=(he+w[a[j].to])%mod1;
}
max_w=max(max_w,max1*max2);
}
int main()
{
//freopen("link.in","r",stdin);
//freopen("link.out","w",stdout);
int u,v;
scanf("%d",&n);
for(int i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
a[++num].next=h[u];
a[num].to=v;
h[u]=num;
a[++num].next=h[v];
a[num].to=u;
h[v]=num;
}
for(int i=1;i<=n;i++)
scanf("%d",&w[i]);
for(int i=1;i<=n;i++)
deliver(i);
sum=(2*sum)%mod1; //两个方向,所以乘二
printf("%d %d\n",max_w,sum);
// fclose(stdin);fclose(stdout);
return 0;
}