#include <bits/stdc++.h>   using namespace std;   template <typename T>   T cross(complex<T> a, complex<T> b) {     return imag(conj(a) * b);   }   template <typename T>   T dot(complex<T> a, complex<T> b) {     return real(conj(a) * b);   }   struct __Query {     static bool query;   };   bool __Query::query = false;   template <typename T>   struct Point {     complex<T> p;     mutable function<const complex<T> *()> succ;     bool operator<(const Point &rhs) const {       const complex<T> &q = rhs.p;       if (!__Query::query) {         if (real(p) != real(q)) return real(p) < real(q);         return imag(p) < imag(q);       }       const complex<T> *s = succ();       if (!s) return false;       return dot(p - *s, q) < 0;     }   };   template <typename T, int turn>   struct half_hull : public set<Point<T>> {     using set<Point<T>>::begin;     using set<Point<T>>::insert;     using set<Point<T>>::end;     using set<Point<T>>::lower_bound;     using set<Point<T>>::empty;     using set<Point<T>>::erase;     using typename set<Point<T>>::iterator;     complex<T> extreme(const complex<T> &p) const {       assert(!empty() && turn * imag(p) >= 0);       __Query::query = true;       auto pos = lower_bound(Point<T>{p});       __Query::query = false;       assert(pos != end());       return pos->p;     }     void insert(const complex<T> &p) {       auto y = insert(Point<T>{p}).first;       if (y == end()) return;       y->succ = [=] { return next(y) == end() ? nullptr : &next(y)->p; };       if (bad(y)) {         erase(y);         return;       }       while (y != begin() && bad(prev(y))) erase(prev(y));       while (next(y) != end() && bad(next(y))) erase(next(y));     }       private:     bool bad(iterator y) {       if (y == begin() || y == end()) return false;       auto x = prev(y), z = next(y);       if (z == end()) return false;       return cross(y->p - x->p, z->p - x->p) * turn >= 0;     }   };   template <typename T>   struct convex_hull_trick {     void insert(const complex<T> &p) {       lower_hull.insert(p);       upper_hull.insert(p);     }     complex<T> extreme(const complex<T> &p) const {       if (std::imag(p) < 0) return lower_hull.extreme(p);       return upper_hull.extreme(p);     }     long long get(const complex<T> &p) const {       if (upper_hull.empty()) return 0LL;       return dot(p, extreme(p));     }       private:     half_hull<T, +1> upper_hull;     half_hull<T, -1> lower_hull;   };   long long solve(vector<vector<int>> &adj, int root = 0) {     int n = adj.size();     vector<long long> sz(n), sz2(n), ssz(n);     long long ans = 0;     function<void(int, int)> dfs = [&](int u, int p) {       sz[u] = 1;       for (auto v : adj[u])         if (v != p) {           dfs(v, u);           sz[u] += sz[v];         }     };     function<void(int, int)> dfs2 = [&](int u, int p) {       sz2[u] += sz[u] * sz[u];       for (auto v : adj[u])         if (v != p) {           sz2[v] += sz2[u];           ssz[v] += ssz[u] + sz[v] * sz[u];           dfs2(v, u);         }     };     function<long long(int, int)> dfs3 = [&](int u, int p) {       convex_hull_trick<long long> cht;       long long ret = -sz2[u] + ssz[u];       for (auto v : adj[u])         if (v != p) {           long long temp = dfs3(v, u);           ret = max(ret, temp);           long long r = sz[v] * n + sz2[u] - ssz[v] + temp;           ans = max(ans, r);           ans = max(ans, r + cht.get({1LL, -sz[v]}));           cht.insert({r, sz[v]});         }       return ret;     };     dfs(root, -1);     dfs2(root, -1);     dfs3(root, -1);     return ans;   }   int main() {     ios_base::sync_with_stdio(0), cin.tie(0);     int n;     cin >> n;     vector<vector<int>> adj(n);     for (int i = 1, u, v; i < n; ++i) {       cin >> u >> v;       --u, --v;       adj[u].push_back(v);       adj[v].push_back(u);     }     long long ans = n * (n - 1LL) / 2 + solve(adj);     cout << ans <<   n ;     return 0;   }