读完题我们会发现此题有树结构。
我们以1为根结点。
假设我们已经做完了x号节点(x可以是叶子节点)的儿子们(y号节点),
我们就在x号节点的tot加上y的tot。
设maxx为与x连边的节点中点权最大值,
每次maxx与y的点权的乘积就可能是最大值。
设sum为与x连边的节点中点权之和,x的tot加上sum与y的点权的乘积,
这样就能不重复的统计所有序点对的联合权值。自己模拟一下就可以知道。
返回最大值(maxx)和tot

#include<cstdio>
#include<algorithm>
using namespace std;

const int p=10007,M=200010;
struct bian{int y,gg;}b[M<<1];
struct lol{int tot,maxx;};
int h[M],a[M],len=0;

void ins(int x,int y)
{
    b[++len].y=y;b[len].gg=h[x];
    h[x]=len;
}

lol dfs(int x,int fa)
{
    lol ans;
    int maxx,sum;
    sum=maxx=a[fa];
    ans.tot=ans.maxx=0;
    for(int i=h[x];i;i=b[i].gg)
    {
        int y=b[i].y;
        if(fa==y)continue;
        lol k=dfs(y,x);
        ans.maxx=max(ans.maxx,k.maxx);
        ans.tot=(ans.tot+k.tot)%p;
        ans.tot=(ans.tot+sum*a[y]%p)%p;
        sum=(sum+a[y])%p;

        ans.maxx=max(maxx*a[y],ans.maxx);
        maxx=max(a[y],maxx);    
    }

    return ans;
}

int main()
{
    int n;scanf("%d",&n);
    for(int i=1;i<n;i++)
    {
        int x,y;scanf("%d %d",&x,&y);
        if(x>y){x^=y;y^=x;x^=y;}//swap
        ins(x,y);ins(y,x);
    }
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    lol ans=dfs(1,0);
    printf("%d %d",ans.maxx,(ans.tot<<1)%p);
    return 0;
}