#include <bits/stdc++.h>
#pragma GCC optimize("O3")
const double PI = acos(-1);
template <class A, class B>
std::ostream &operator<<(std::ostream &st, const std::pair<A, B> p) {
  st << "(" << p.first << ", " << p.second << ")";
  return st;
}
using namespace std;
const int MAXV = 150000 + 10, MAXE = 2 * MAXV;
const long long MAXA = MAXV * (MAXV + 1LL) * 1e6 + 10, oo = 1LL << 60;
std::vector<int> G[MAXV];
bool dead[MAXV];
int siz[MAXV], mx[MAXV];
int A[MAXV], n;
using line = pair<long long, long long>;
struct node {
  node *l, *r;
  line v;
  node() {
    l = r = 0;
    v = line(0, -oo);
  }
};
auto f = [](const line &A, const long long &x) {
  return A.first * x + A.second;
};
void add_line(node *&cur, line nw, long long l = 0, long long r = MAXA) {
  if (!cur) {
    cur = new node();
    cur->v = nw;
    return;
  }
  if (l == r) {
    if (f(nw, l) > f(cur->v, l)) cur->v = nw;
    return;
  }
  long long m = l + (r - l) / 2;
  bool lef = f(nw, l) > f(cur->v, l);
  bool mid = f(nw, m) > f(cur->v, m);
  if (mid) {
    swap(cur->v, nw);
  }
  if (lef != mid) {
    add_line(cur->l, nw, l, m);
  } else {
    add_line(cur->r, nw, m + 1, r);
  }
}
long long get(node *cur, long long x, long long l = 0, long long r = MAXA) {
  if (!cur) return -oo;
  long long m = l + (r - l) / 2;
  long long ret = 0;
  if (l == r) {
    ret = f(cur->v, x);
  } else if (x < m) {
    ret = max(f(cur->v, x), get(cur->l, x, l, m));
  } else {
    ret = max(f(cur->v, x), get(cur->r, x, m + 1, r));
  }
  assert(ret >= 0);
  return ret;
}
int floodfill(int u, int p) {
  siz[u] = 1;
  mx[u] = 0;
  for (int v : G[u])
    if (v != p && !dead[v]) {
      floodfill(v, u);
      siz[u] += siz[v];
      mx[u] = max(mx[u], siz[v]);
    }
  return siz[u];
}
int get_center(int u, int p, int s) {
  mx[u] = max(mx[u], s - siz[u]);
  int c = u;
  for (int v : G[u])
    if (v != p && !dead[v]) {
      int g = get_center(v, u, s);
      if (mx[g] < mx[c]) c = g;
    }
  return c;
}
long long query(int u, int p, long long w_sum_up, long long sum_up, int len_up,
                long long w_sum_down, long long sum_down, int len_down,
                node *up, node *down) {
  len_down++;
  sum_down += A[u];
  w_sum_down += A[u] * (long long)len_down;
  len_up++;
  sum_up += A[u];
  w_sum_up += sum_up;
  long long ret =
      max(get(up, sum_down) + w_sum_down, get(down, len_up) + w_sum_up);
  assert(ret >= max(w_sum_down, w_sum_up));
  for (int v : G[u])
    if (v != p && !dead[v])
      ret = max(ret, query(v, u, w_sum_up, sum_up, len_up, w_sum_down, sum_down,
                           len_down, up, down));
  return ret;
}
void insert(int u, int p, long long w_sum_up, long long sum_up, int len_up,
            long long w_sum_down, long long sum_down, int len_down, node *&up,
            node *&down) {
  len_down++;
  sum_down += A[u];
  w_sum_down += A[u] * (long long)len_down;
  len_up++;
  sum_up += A[u];
  w_sum_up += sum_up;
  add_line(up, line(len_up, w_sum_up));
  add_line(down, line(sum_down, w_sum_down));
  for (int v : G[u])
    if (v != p && !dead[v])
      insert(v, u, w_sum_up, sum_up, len_up, w_sum_down, sum_down, len_down, up,
             down);
}
long long DC(int u) {
  u = get_center(u, 0, floodfill(u, 0));
  long long ret = A[u];
  node *up = 0, *down = 0;
  add_line(up, line(1, A[u]));
  add_line(down, line(0, 0));
  for (int v : G[u])
    if (!dead[v]) {
      ret = max(ret, query(v, u, A[u], A[u], 1, 0, 0, 0, up, down));
      insert(v, u, A[u], A[u], 1, 0, 0, 0, up, down);
    }
  dead[u] = 1;
  for (int v : G[u])
    if (!dead[v]) {
      ret = max(ret, DC(v));
    }
  return ret;
}
int main() {
  scanf("%d", &n);
  for (int e = 0; e < (n - 1); e++) {
    int a, b;
    scanf("%d %d", &a, &b);
    G[a].push_back(b);
    G[b].push_back(a);
  }
  for (int i = 1; i <= n; i++) scanf("%d", A + i);
  printf("%lld\n", DC(1));
  return 0;
}
