/*
自己打暴力,看了看不用打LCA只处理倍增数组
然后就10分了......
神奇的LCA 估计打了能有60分
只能看峰峰...
*/
#include<iostream>
#include<cstdio>
#include<cstdlib>
#define maxn 200001
#define mod 10007
using namespace std;
int n,m,cnt,ans,num,tot,x,y,z,maxx;
int head[maxn],deep[maxn],dis[maxn];
int f[maxn][20];
struct node
{
int from;
int to;
int dis;
int next;
}e[maxn*2];
int init()
{
int x=0,f=1;char c=getchar();
while(c>‘9‘||c<‘0‘){if(c==‘-‘)f=-1;c=getchar();}
while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘;c=getchar();}
return x*f;
}
void add(int from,int to)
{
e[++num].from=from;
e[num].to=to;
e[num].next=head[from];
head[from]=num;
}
void get_fa()
{
for(int j=1;j<=20;j++)
for(int i=1;i<=n;i++)
f[i][j]=f[f[i][j-1]][j-1];
}
void Dfs(int from,int now,int cnt)
{
f[now][0]=from;deep[now]=cnt;
for(int i=head[now];i;i=e[i].next)
{
int v=e[i].to;
if(v!=from)
Dfs(now,v,cnt+1);
}
}
int main()
{
n=init();
for(int i=1;i<n;i++)
{
x=init();y=init();
add(x,y);add(y,x);
}
for(int i=1;i<=n;i++)
dis[i]=init();
Dfs(1,1,0);
get_fa();
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
if(j==i) continue;
{
if(deep[i]==deep[j]&&f[i][0]==f[j][0]||deep[i]-deep[j]==2&&f[i][1]==j||deep[j]-deep[i]==2&&f[j][1]==i)
{
tot+=dis[i]*dis[j];
maxx=max(maxx,dis[i]*dis[j]);
}
}
}
printf("%d %d\n",maxx,tot%mod);
}
/*
峰峰果然是大神 果然裸地LCA枚举60分
开始的思路 求出每两个点之间的距离(其实枚举两个点就T了)
统计为2 的点对 然后统计答案
倍增LCA的话 是O(n+n*n) 后面的n*n是枚举那两个点
T了 60分
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 200010
using namespace std;
int n,w[maxn],fa[maxn][20],head[maxn],num,dep[maxn],ans,sum;
struct node
{
int u,v,pre;
}e[maxn*2];
int init()
{
int x=0;char s=getchar();
while(s<‘0‘||s>‘9‘)s=getchar();
while(s>=‘0‘&&s<=‘9‘){x=x*10+s-‘0‘;s=getchar();}
return x;
}
void Add(int from,int to)
{
num++;
e[num].u=from;
e[num].v=to;
e[num].pre=head[from];
head[from]=num;
}
void Dfs(int now,int from,int c)
{
fa[now][0]=from;
dep[now]=c;
for(int i=head[now];i;i=e[i].pre)
if(e[i].v!=from)
Dfs(e[i].v,now,c+1);
}
void Get_fa()
{
for(int j=1;j<=17;j++)
for(int i=1;i<=n;i++)
fa[i][j]=fa[fa[i][j-1]][j-1];
}
int Get_a(int a,int t)
{
for(int i=1;i<=t;i++)
a=fa[a][0];
return a;
}
int LCA(int a,int b)
{
if(dep[a]<dep[b])swap(a,b);
a=Get_a(a,dep[a]-dep[b]);
if(a==b)return a;
for(int i=17;i>=0;i--)
if(fa[a][i]!=fa[b][i])
{
a=fa[a][i];
b=fa[b][i];
}
return fa[a][0];
}
int main()
{
//freopen("linkb.in","r",stdin);
//freopen("linkb.out","w",stdout);
n=init();
int u,v;
for(int i=1;i<=n-1;i++)
{
u=init();v=init();
Add(u,v);Add(v,u);
}
for(int i=1;i<=n;i++)
w[i]=init();
Dfs(1,1,0);
Get_fa();
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
{
int anc=LCA(i,j);
int deep=dep[i]+dep[j]-2*dep[anc];
if(deep==2)
{
ans=max(ans,w[i]*w[j]);
sum=(sum+w[i]*w[j])%10007;
}
}
printf("%d %d\n",ans,sum*2%10007);
return 0;
}
/*
因为默认的边权值是1 所以距离为2的点也就是从同一个点出发的两个
这样我们不需要n*n的枚举点 我们统计每个点之间相连的
然后两两组合 这里会发现 又跑慢了 70分
假设点x直接相连的点有三个 权值分别是a b c
那么我们两两组合后总权值是ab+bc+ac
会发现这里和之前用线段树求区间两两元素之和是一样的
根据数学公式 (a+b+c)^2-a^2-b^2-c^2=2*(ab+bc+ac)
这样我们就可以很快地求出权值和 至于最大的嘛 那肯定是最大的两个点权之积
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 200010
#define mod 10007
using namespace std;
int n,w[maxn],head[maxn],num,ans,sum;
struct node
{
int u,v,pre;
}e[maxn*2];
int cmp(int x,int y)
{
return x>y;
}
int init()
{
int x=0;char s=getchar();
while(s<‘0‘||s>‘9‘)s=getchar();
while(s>=‘0‘&&s<=‘9‘){x=x*10+s-‘0‘;s=getchar();}
return x;
}
void Add(int from,int to)
{
num++;
e[num].u=from;
e[num].v=to;
e[num].pre=head[from];
head[from]=num;
}
int main()
{
//freopen("linkb.in","r",stdin);
//freopen("linkb.out","w",stdout);
n=init();
int x,y;
for(int i=1;i<=n-1;i++)
{
x=init();y=init();
Add(x,y);Add(y,x);
}
for(int i=1;i<=n;i++)
w[i]=init();
for(int u=1;u<=n;u++)
{
int p[maxn],l=0,tmp=0,s=0;
for(int i=head[u];i;i=e[i].pre)
p[++l]=w[e[i].v];
sort(p+1,p+1+l,cmp);
ans=max(ans,p[1]*p[2]);
for(int i=1;i<=l;i++)
{
tmp=(tmp+p[i]*p[i]%mod)%mod;
s=(s+p[i]%mod)%mod;
}
sum=(sum+(s*s-tmp)%mod)%mod;
}
printf("%d %d\n",ans,sum);
return 0;
}