#include <bits/stdc++.h>   using namespace std;   using ll = long long;   template <typename T>   using posteriority_queue = priority_queue<T, vector<T>, greater<T> >;   const int INF = 0x3f3f3f3f;   const ll LINF = 0x3f3f3f3f3f3f3f3fLL;   const double EPS = 1e-8;   const int MOD = 1000000007;   const int dy[] = {1, 0, -1, 0}, dx[] = {0, -1, 0, 1};   const int dy8[] = {1, 1, 0, -1, -1, -1, 0, 1},             dx8[] = {0, -1, -1, -1, 0, 1, 1, 1};   template <typename T, typename U>   inline bool chmax(T &a, U b) {     return a < b ? (a = b, true) : false;   }   template <typename T, typename U>   inline bool chmin(T &a, U b) {     return a > b ? (a = b, true) : false;   }   template <typename T>   void unique(vector<T> &a) {     a.erase(unique((a).begin(), (a).end()), a.end());   }   struct IOSetup {     IOSetup() {       cin.tie(nullptr);       ios_base::sync_with_stdio(false);       cout << fixed << setprecision(20);     }   } iosetup;   using CostType = ll;   struct Edge {     int src, dst;     CostType cost;     Edge(int src, int dst, CostType cost = 0) : src(src), dst(dst), cost(cost) {}     inline bool operator<(const Edge &rhs) const {       return cost != rhs.cost ? cost < rhs.cost              : dst != rhs.dst ? dst < rhs.dst                               : src < rhs.src;     }     inline bool operator<=(const Edge &rhs) const { return !(rhs < *this); }     inline bool operator>(const Edge &rhs) const { return rhs < *this; }     inline bool operator>=(const Edge &rhs) const { return !(*this < rhs); }   };   struct CentroidDecomposition {     int root;     vector<vector<int> > comp;     vector<int> par;     CentroidDecomposition(const vector<vector<Edge> > &graph) : graph(graph) {       int n = graph.size();       alive.assign(n, true);       subtree.resize(n);       comp.resize(n);       par.assign(n, -1);       root = build(0);     }       private:     const vector<vector<Edge> > graph;     vector<bool> alive;     vector<int> subtree;     int build(int s) {       int centroid = search_centroid(-1, s, calc_subtree(-1, s) / 2);       alive[centroid] = false;       for (const Edge &e : graph[centroid]) {         if (alive[e.dst]) {           comp[centroid].emplace_back(build(e.dst));           par[e.dst] = centroid;         }       }       alive[centroid] = true;       return centroid;     }     int calc_subtree(int par, int ver) {       subtree[ver] = 1;       for (const Edge &e : graph[ver]) {         if (e.dst != par && alive[e.dst])           subtree[ver] += calc_subtree(ver, e.dst);       }       return subtree[ver];     }     int search_centroid(int par, int ver, int half) {       for (const Edge &e : graph[ver]) {         if (e.dst != par && alive[e.dst]) {           if (subtree[e.dst] > half) return search_centroid(ver, e.dst, half);         }       }       return ver;     }   };   template <typename T>   struct LiChaoTree {     struct Line {       T a, b;       Line(T a, T b) : a(a), b(b) {}       T f(T x) { return a * x + b; }     };     LiChaoTree(const vector<T> &xs_, const T TINF, bool is_minimized = true)         : xs(xs_), TINF(TINF), is_minimized(is_minimized) {       sort((xs).begin(), (xs).end());       unique(xs);       int sz = xs.size();       while (n < sz) n <<= 1;       xs.resize(n, TINF);       Line unity(0, is_minimized ? TINF : -TINF);       dat.assign(n << 1, unity);     }     void add(T a, T b) {       Line line(a, b);       add(line, 1, 0, n);     }     void add(T a, T b, T left, T right) {       int l = lower_bound((xs).begin(), (xs).end(), left) - xs.begin(),           r = lower_bound((xs).begin(), (xs).end(), right) - xs.begin();       int len, node_l = l, node_r = r;       for (l += n, r += n, len = 1; l < r; l >>= 1, r >>= 1, len <<= 1) {         if (l & 1) {           Line line(a, b);           add(line, l++, node_l, node_l + len);           node_l += len;         }         if (r & 1) {           Line line(a, b);           node_r -= len;           add(line, --r, node_r, node_r + len);         }       }     }     T query(T x) {       int node = lower_bound((xs).begin(), (xs).end(), x) - xs.begin();       node += n;       T res = dat[node].f(x);       while (node >>= 1) {         if (is_minimized) {           chmin(res, dat[node].f(x));         } else {           chmax(res, dat[node].f(x));         }       }       return res;     }       private:     const T TINF;     bool is_minimized;     int n = 1;     vector<T> xs;     vector<Line> dat;     void add(Line &line, int node, int left, int right) {       bool l = dat[node].f(xs[left]) <= line.f(xs[left]),            r = dat[node].f(xs[right - 1]) <= line.f(xs[right - 1]);       if (l && r) {         if (!is_minimized) swap(dat[node], line);         return;       }       if (!l && !r) {         if (is_minimized) swap(dat[node], line);         return;       }       int mid = (left + right) >> 1;       bool m = line.f(xs[mid]) < dat[node].f(xs[mid]);       if (is_minimized) {         if (m) swap(dat[node], line);       } else {         if (!m) swap(dat[node], line);       }       if (line.f(xs[left]) <= dat[node].f(xs[left])) {         if (is_minimized) {           add(line, node << 1, left, mid);         } else {           add(line, (node << 1) + 1, mid, right);         }       } else {         if (is_minimized) {           add(line, (node << 1) + 1, mid, right);         } else {           add(line, node << 1, left, mid);         }       }     }   };   int main() {     int n;     cin >> n;     vector<vector<Edge> > graph(n);     for (int _ = (0); _ < (n - 1); ++_) {       int u, v;       cin >> u >> v;       --u;       --v;       graph[u].emplace_back(u, v);       graph[v].emplace_back(v, u);     }     vector<int> a(n);     for (int i = (0); i < (n); ++i) cin >> a[i];     CentroidDecomposition cent(graph);     vector<bool> visited(n, false);     ll ans = 0;     function<void(int)> dfs = [&](int root) {       visited[root] = true;       chmax(ans, a[root]);       vector<vector<ll> > sum_a, psum_a;       vector<vector<pair<ll, int> > > psum_b;       function<void(int, int, int, ll, ll, ll, int)> dfs2 =           [&](int par, int ver, int idx, ll sum, ll A, ll B, int len) {             sum += a[ver];             A += 1LL * a[ver] * len;             B += sum - a[root];             bool leaf = true;             for (const Edge &e : graph[ver]) {               if (e.dst == par || visited[e.dst]) continue;               dfs2(ver, e.dst, idx, sum, A, B, len + 1);               leaf = false;             }             if (leaf) {               sum_a[idx].emplace_back(sum);               psum_a[idx].emplace_back(A);               psum_b[idx].emplace_back(B, len - 1);             }           };       for (const Edge &e : graph[root]) {         if (visited[e.dst]) continue;         int sz = sum_a.size();         sum_a.emplace_back();         psum_a.emplace_back();         psum_b.emplace_back();         dfs2(-1, e.dst, sz, a[root], a[root], 0, 2);       }       int m = sum_a.size();       vector<ll> xs;       for (int i = (0); i < (m); ++i) {         for (ll e : sum_a[i]) xs.emplace_back(e);         for (ll e : psum_a[i]) chmax(ans, e);         for (auto pr : psum_b[i])           chmax(ans, pr.first + 1LL * a[root] * (pr.second + 1));       }       if (!xs.empty()) {         sort((xs).begin(), (xs).end());         unique(xs);         LiChaoTree<ll> lct1(xs, LINF, false);         for (int i = (0); i < (m); ++i) {           int sz = sum_a[i].size();           for (int j = (0); j < (sz); ++j)             chmax(ans, lct1.query(sum_a[i][j]) + psum_a[i][j]);           for (int j = (0); j < (sz); ++j)             lct1.add(psum_b[i][j].second, psum_b[i][j].first);         }         LiChaoTree<ll> lct2(xs, LINF, false);         for (int i = m - 1; i >= 0; --i) {           int sz = sum_a[i].size();           for (int j = (0); j < (sz); ++j)             chmax(ans, lct2.query(sum_a[i][j]) + psum_a[i][j]);           for (int j = (0); j < (sz); ++j)             lct2.add(psum_b[i][j].second, psum_b[i][j].first);         }       }       for (int e : cent.comp[root]) dfs(e);     };     dfs(cent.root);     cout << ans <<   n ;     return 0;   }