#include <bits/stdc++.h>
using namespace std;
template <typename T, typename NT = T>
class Graph {
 public:
  struct EDGE {
    int to;
    T val;
    EDGE() {}
    EDGE(int TO, T V) { to = TO, val = V; }
    void debug() { printf("to=%d val=%d\n", to, (int)val); }
  };
  int n;
  vector<vector<EDGE>> g;
  vector<NT> nv;
  vector<int> in, out;
  Graph() {}
  Graph(int N) { init(N); }
  inline void add(int x, int y, T v = 1) {
    in[y]++, out[x]++;
    g[x].push_back(EDGE(y, v));
  }
  void debug() {
    for (int x = 1; x <= n; x++) {
      printf("x=%d nv=%d\n", x, (int)nv[x]);
      for (auto e : g[x]) e.debug();
    }
    puts("");
  }
  template <typename Type>
  Type trans() const {
    Type ans(n);
    ans.n = n;
    ans.in = in;
    ans.out = out;
    ans.g = g;
    ans.nv = nv;
    return ans;
  }

 private:
  void init(int N) {
    n = N;
    g.clear();
    nv.clear();
    in.clear();
    out.clear();
    g.resize(N + 1);
    nv.resize(N + 1);
    in.resize(N + 1);
    out.resize(N + 1);
  }

 protected:
  bool equalT(const T &x, const T &y) const { return (!(x < y)) && (!(y < x)); }
};
template <typename T, typename NT = T, int STA = 0>
class Forest : public Graph<T, NT> {
 public:
  using Graph<T, NT>::g;
  using Graph<T, NT>::n;
  vector<int> root, siz, deep, fa, wson, bg, ed, nodeList;
  vector<T> depv;
  vector<bool> vis;
  Forest() {}
  Forest(int N) : Graph<T, NT>(N) { init(n); }
  void setTreeInfo(int s) {
    if (s) {
      dfs(s, 0);
      root.push_back(s);
    } else {
      for (int i = 1; i <= n; i++) {
        if (!vis[i]) {
          dfs(i, 0);
          root.push_back(i);
        }
      }
    }
  }
  int getCentre(int s) {
    assert(!vis[s]);
    assert(STA == 2);
    nodeList[0] = s;
    fa[s] = -1;
    int p = 1;
    for (int i = 0; i < p; i++) {
      int x = nodeList[i];
      for (auto e : g[x]) {
        if (!vis[e.to] && fa[x] != e.to) {
          fa[nodeList[p++] = e.to] = x;
        }
      }
      siz[x] = 1, wson[x] = 0;
    }
    for (int i = p - 1; i >= 0; i--) {
      int x = nodeList[i];
      wson[x] = max(wson[x], p - siz[x]);
      if (wson[x] * 2 <= p) return x;
      siz[fa[x]] += siz[x];
      wson[fa[x]] = max(wson[fa[x]], siz[x]);
    }
    return 0;
  }

 private:
  int cnt;
  void init(int N) {
    if (STA < 2) {
      root.clear();
      vis.clear();
      depv.clear();
      siz.resize(N + 1);
      deep.resize(N + 1);
      fa.resize(N + 1);
      bg.resize(N + 1);
      ed.resize(N + 1);
      vis.resize(N + 1);
      depv.resize(N + 1);
      nodeList.resize(1);
      deep[0] = cnt = 0;
    } else {
      vis.clear();
      vis.resize(N + 1);
      fa.resize(N + 1);
      siz.resize(N + 1);
      nodeList.resize(N + 1);
    }
    if (!STA) return;
    wson.resize(N + 1);
  }
  void dfs(int x, int f) {
    vis[x] = true;
    deep[x] = deep[f] + 1;
    fa[x] = f;
    siz[x] = 1;
    wson[x] = 0;
    bg[x] = ++cnt;
    if (STA != 1) nodeList.push_back(x);
    for (auto e : g[x]) {
      if (e.to != f) {
        depv[e.to] = depv[x] + e.val;
        dfs(e.to, x);
        siz[x] += siz[e.to];
        if (STA != 1) continue;
        if (siz[e.to] > siz[wson[x]]) wson[x] = e.to;
      }
    }
    ed[x] = cnt;
  }
};
template <typename T, T DK = T(0), T DB = T(0), class CMP = greater<T>>
class LiChaoSegmentTree {
 public:
  int n;
  LiChaoSegmentTree() {}
  LiChaoSegmentTree(int N, T *POSV = NULL) {
    n = N;
    posv.resize(N + 1);
    if (POSV == NULL) {
      for (int i = 1; i <= n; i++) posv[i] = T(i);
    } else {
      for (int i = 1; i <= n; i++) posv[i] = POSV[i];
    }
    mv.resize((N << 2) + 1);
    v.resize((N << 2) + 1);
    build(1, N, 1);
  }
  void insert(int l, int r, int rt, int nl, int nr, pair<T, T> p) {
    bool staL = cmpPos(l, v[rt], p);
    bool staR = cmpPos(r, v[rt], p);
    if (staL && staR) return;
    int mid = (l + r) >> 1;
    if (nl <= l && nr >= r) {
      if ((!staL) && (!staR)) {
        v[rt] = p;
      } else {
        if (staL) {
          if (cmpPos(mid, v[rt], p))
            insert(mid + 1, r, rt << 1 | 1, nl, nr, p);
          else {
            swap(p, v[rt]);
            insert(l, mid, rt << 1, nl, nr, p);
          }
        } else {
          if (!cmpPos(mid, v[rt], p)) {
            swap(p, v[rt]);
            insert(mid + 1, r, rt << 1 | 1, nl, nr, p);
          } else
            insert(l, mid, rt << 1, nl, nr, p);
        }
      }
    } else {
      if (nl <= mid) insert(l, mid, rt << 1, nl, nr, p);
      if (nr > mid) insert(mid + 1, r, rt << 1 | 1, nl, nr, p);
    }
    updata(l, r, rt);
  }
  void insert(int nl, int nr, pair<T, T> p) {
    assert(nl <= nr);
    assert(1 <= nl && nr <= n);
    insert(1, n, 1, nl, nr, p);
  }
  void insert(pair<T, T> p) { insert(1, n, p); }
  T query(int l, int r, int rt, int nl, int nr) {
    if (nl <= l && nr >= r) {
      return mv[rt];
    }
    nl = max(nl, l), nr = min(nr, r);
    T ans = getMx(eval(nl, v[rt]), eval(nr, v[rt]));
    int mid = (l + r) >> 1;
    if (nl <= mid) ans = getMx(ans, query(l, mid, rt << 1, nl, nr));
    if (nr > mid) ans = getMx(ans, query(mid + 1, r, rt << 1 | 1, nl, nr));
    return ans;
  }
  T query(int nl, int nr) {
    assert(nl <= nr);
    assert(1 <= nl && nr <= n);
    return query(1, n, 1, nl, nr);
  }

 private:
  CMP cmp;
  vector<pair<T, T>> v;
  vector<T> posv, mv;
  pair<T, T> Default = make_pair(DK, DB);
  inline T eval(int pos, pair<T, T> p) {
    return p.first * posv[pos] + p.second;
  }
  inline T getMx(const T &x, const T &y) { return cmp(x, y) ? x : y; }
  inline bool cmpPos(int pos, pair<T, T> x, pair<T, T> y) {
    return cmp(eval(pos, x), eval(pos, y));
  }
  void updata(int l, int r, int rt) {
    assert(rt < v.size());
    mv[rt] = getMx(eval(l, v[rt]), eval(r, v[rt]));
    if (l != r) mv[rt] = getMx(mv[rt], getMx(mv[rt << 1], mv[rt << 1 | 1]));
  }
  void build(int l, int r, int rt) {
    v[rt] = Default;
    if (l == r) {
      mv[rt] = eval(l, v[rt]);
      return;
    }
    int mid = (l + r) >> 1;
    build(l, mid, rt << 1);
    build(mid + 1, r, rt << 1 | 1);
    updata(l, r, rt);
  }
};
const int maxn = 150000 + 5;
int n;
long long ans = 0;
Forest<int, long long, 2> F;
long long dis[maxn], val[maxn];
long long rval[maxn];
int dep[maxn];
vector<vector<int>> Q;
vector<int> q;
int mxdp = 0;
pair<int, int> stk[maxn];
void dfs(int x, int fa) {
  int top = 1;
  stk[0] = make_pair(x, fa);
  for (int i = 0; i < top; i++) {
    x = stk[i].first, fa = stk[i].second;
    bool flag = true;
    dis[x] = dis[fa] + F.nv[x];
    dep[x] = dep[fa] + 1;
    val[x] = val[fa] + dis[x];
    rval[x] = F.nv[x] * dep[x] + rval[fa];
    for (auto e : F.g[x]) {
      if (!F.vis[e.to] && fa != e.to) {
        flag = false;
        stk[top++] = (make_pair(e.to, x));
      }
    }
    mxdp = max(mxdp, dep[x]);
    if (flag) q.push_back(x);
  }
}
void solve(int x) {
  F.vis[x] = true;
  val[x] = dis[x] = rval[x] = dep[x] = 0;
  q.clear();
  Q.clear();
  q.push_back(x);
  Q.push_back(q);
  mxdp = 0;
  for (auto e : F.g[x])
    if (!F.vis[e.to]) {
      q.clear();
      dfs(e.to, x);
      Q.push_back(q);
    }
  LiChaoSegmentTree<long long> LC(mxdp + 1);
  for (int i = 0; i < Q.size(); i++) {
    for (auto now : Q[i]) {
      long long tv = F.nv[x] * (dep[now] + 1) + val[now];
      ans = max(ans, tv + LC.query(dep[now] + 1, dep[now] + 1));
    }
    for (auto now : Q[i]) {
      LC.insert(make_pair(dis[now], rval[now]));
    }
  }
  LC = LiChaoSegmentTree<long long>(mxdp + 1);
  for (int i = Q.size() - 1; i >= 0; i--) {
    for (auto now : Q[i]) {
      long long tv = F.nv[x] * (dep[now] + 1) + val[now];
      ans = max(ans, tv + LC.query(dep[now] + 1, dep[now] + 1));
    }
    for (auto now : Q[i]) {
      LC.insert(make_pair(dis[now], rval[now]));
    }
  }
  for (auto e : F.g[x])
    if (!F.vis[e.to]) {
      solve(F.getCentre(e.to));
    }
}
int main() {
  scanf("%d", &n);
  F = Forest<int, long long, 2>(n);
  for (int i = 1; i < n; i++) {
    int x, y;
    scanf("%d%d", &x, &y);
    F.add(x, y);
    F.add(y, x);
  }
  for (int i = 1; i <= n; i++) scanf("%lld", &F.nv[i]);
  solve(F.getCentre(1));
  printf("%lld\n", ans);
}
