#include<cstdio> #include<iostream> usingnamespace std; #define gc c = getchar() intread(){ int x = 0, f = 1; char gc; for (; !isdigit(c); gc) if (c == '-') f = -1; for (; isdigit(c); gc) x = x * 10 + c - '0'; return x * f; } #undef gc constint MAXN = 200005; constint P = 10007; int n, Ans, ans, a[MAXN]; int nedge, head[MAXN]; structEdge { int to, nxt; } edge[MAXN * 2]; // 边表2倍勿忘 voidadd(int x, int y){ edge[++nedge].to = y; edge[nedge].nxt = head[x]; head[x] = nedge; } voidcalc(int k){ // 关键函数 int Max = 0, Maxx = 0, sum = 0; // Max为与k相连最大的点权值,Maxx为次大值 for (int i = head[k]; i; i = edge[i].nxt) { int u = edge[i].to; if (a[u] > Max) { Maxx = Max; Max = a[u]; } elseif (a[u] > Maxx) Maxx = a[u]; // 更新最大、次大值 sum = (sum + a[u]) % P; // 累加权值和 } for (int i = head[k]; i; i = edge[i].nxt) { int u = edge[i].to; ans = (ans + (sum - a[u]) * a[u]) % P; // 当前点对答案的贡献为(除自己外总和)*(自己的权值) } Ans = max(Ans, Max * Maxx); // 当前公共点所能产生的最大联合权值为(最大值)*(次大值) } intmain(){ int n = read(); for (int i = 1; i < n; i++) { int x = read(), y = read(); add(x, y), add(y, x); } // 前向星建边 for (int i = 1; i <= n; i++) a[i] = read(); // 读入点权 for (int i = 1; i <= n; i++) calc(i); // 枚举每个公共点计算 printf("%d %d", Ans, (ans + P) % P); // 因为我们在统计的时候是减一个数,所以可能会出现ans小于0的情况,要(ans+P)%P }