#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;
}
