#include <bits/stdc++.h>
using namespace std;
using uint = unsigned int;
using ll = long long;
using ull = unsigned long long;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
template <typename T1, typename T2>
ostream &operator<<(ostream &out, const pair<T1, T2> &item) {
  out << '(' << item.first << ", " << item.second << ')';
  return out;
}
template <typename T>
ostream &operator<<(ostream &out, const vector<T> &v) {
  for (const auto &item : v) out << item << ' ';
  return out;
}
const int N = 500010;
template <class T = pll, class U = ll>
struct CHT {
  struct Frac {
    ll x, y;
    Frac(ll _x, ll _y) : x(_x), y(_y) {
      if (y < 0) x = -x, y = -y;
    }
    Frac operator-() const { return Frac(-x, y); }
    bool operator<(const Frac &other) const {
      if (x / y != other.x / other.y) return x / y < other.x / other.y;
      if (x < 0) {
        if (other.x < 0) return -other < -(*this);
        return true;
      }
      if (other.x < 0) return false;
      if (other.x % other.y == 0) return false;
      if (x % y == 0) return true;
      return Frac(other.y, other.x % other.y) < Frac(y, x % y);
    }
  };
  Frac inter(T l1, T l2) {
    return {l2.second - l1.second, l1.first - l2.first};
  }
  int nr = 0;
  vector<T> v;
  void add(T line) {
    if (!v.empty() && v.back().first == line.first) {
      if (v.back().second < line.second) v.back() = line;
      return;
    }
    v.push_back(line);
    ++nr;
  }
  U query(ll x) {
    int l, r, mid;
    for (l = 0, r = nr - 1; l < r;) {
      mid = (l + r) / 2;
      if (inter(v[mid], v[mid + 1]) < Frac(x, 1))
        l = mid + 1;
      else
        r = mid;
    }
    return eval(v[l], x);
  }
  ll eval(T line, ll x) { return line.first * x + line.second; }
};
int n;
ll ans;
int sz[N];
vector<int> adj[N];
ll f(int n) {
  assert(1LL * n * (n - 1) / 2 >= 0);
  return 1LL * n * (n - 1) / 2;
}
void calcSz(int v, int p = -1) {
  sz[v] = 1;
  for (auto u : adj[v])
    if (u != p) {
      calcSz(u, v);
      sz[v] += sz[u];
    }
}
ll dfs(int v, int p = -1) {
  vector<ll> vret;
  vector<pair<pll, ll>> lines;
  for (auto u : adj[v])
    if (u != p) {
      ll s = dfs(u, v);
      vret.push_back(s + f(sz[v] - sz[u]));
      lines.push_back({{sz[u], -1LL * sz[u] * (sz[u] + 1) / 2 - s}, s});
    }
  sort(lines.begin(), lines.end());
  CHT<> cht;
  for (auto line : lines) {
    if (cht.nr >= 1) {
      int nn = n - line.first.first;
      ans = max(ans, 2 * f(n) - line.second - f(nn) + cht.query(nn));
    }
    cht.add(line.first);
  }
  if (vret.empty()) return 0;
  return *min_element(vret.begin(), vret.end());
}
int main() {
  ios_base::sync_with_stdio(false);
  int a, b;
  cin >> n;
  for (int i = 1; i < n; ++i) {
    cin >> a >> b;
    adj[a].push_back(b);
    adj[b].push_back(a);
  }
  if (n == 2) return cout << 2 << '\n', 0;
  for (int i = 1; i <= n; ++i)
    if (adj[i].size() >= 2) {
      calcSz(i);
      dfs(i);
      break;
    }
  cout << ans << '\n';
  return 0;
}
