#include <bits/stdc++.h>
using namespace std;
clock_t __START, __END;
double __TOTALTIME;
void _MS() { __START = clock(); }
void _ME() {
  __END = clock();
  __TOTALTIME = (double)(__END - __START) / CLOCKS_PER_SEC;
  cout << "Time: " << __TOTALTIME << " s" << endl;
}
const double E = 2.718281828;
const double PI = acos(-1.0);
const long long INF = (1LL << 60);
const int inf = (1 << 30);
const double ESP = 1e-9;
const int mod = (int)1e9 + 7;
const int N = (int)15000 + 10;
class mymap {
 public:
  int tot, cnt_loop;
  int head[N], in[N], loop[N], SZ[N];
  int ele[N];
  int ans[N];
  bool is[N], vis[N];
  struct {
    int to, next, dis;
  } edge[N * 2];
  void Init(int n) {
    tot = cnt_loop = 0;
    for (int i = 0; i <= n; ++i) head[i] = in[i] = vis[i] = 0, is[i] = 1;
  }
  void add(int from, int to) {
    ++tot;
    edge[tot].to = to;
    edge[tot].next = head[from];
    head[from] = tot;
  }
  void get_loop(int n) {
    queue<int> q;
    for (int i = 1; i <= n; ++i)
      if (in[i] == 1) q.push(i);
    while (!q.empty()) {
      int now = q.front();
      q.pop();
      is[now] = 0;
      for (int i = head[now]; i; i = edge[i].next) {
        int to = edge[i].to;
        in[to]--;
        if (in[to] == 1) q.push(to);
      }
    }
    for (int i = 1; i <= n; ++i) {
      if (is[i]) {
        q.push(i);
        while (!q.empty()) {
          int now = q.front();
          q.pop();
          loop[++cnt_loop] = now;
          vis[now] = 1;
          bool have = 0;
          for (int j = head[now]; j; j = edge[j].next) {
            int to = edge[j].to;
            if (have) break;
            if (is[to] && !vis[to]) {
              have = 1;
              q.push(to);
            }
          }
        }
        break;
      }
    }
  }
  void dfs1(int u, int fa) {
    SZ[u] = 1;
    for (int i = head[u]; i; i = edge[i].next) {
      int to = edge[i].to;
      if (to != fa && !is[to]) {
        dfs1(to, u);
        SZ[u] += SZ[to];
        ele[u] += ele[to];
      }
    }
    ele[u] += SZ[u];
  }
  void dfs2(int u, int fa, int dep, int root, int id, int n) {
    ans[id] = max(ans[id], ele[u] + dep * (n - SZ[root]));
    for (int i = head[u]; i; i = edge[i].next) {
      int to = edge[i].to;
      if (to != fa && !is[to]) {
        ele[to] = ele[u] - SZ[to] + SZ[root] - SZ[to];
        dfs2(to, u, dep + 1, root, id, n);
      }
    }
  }
} TREE;
int realPos(int now, int len) {
  if (now > len)
    now -= len;
  else if (now < 1)
    now += len;
  return now;
}
int dp1[N][2];
int dp2[N][2];
int32_t main() {
  int n;
  scanf("%d", &n);
  TREE.Init(n);
  for (int i = 1; i <= n; ++i) {
    int u, v;
    scanf("%d%d", &u, &v);
    u++;
    v++;
    TREE.add(u, v);
    TREE.add(v, u);
    TREE.in[u]++;
    TREE.in[v]++;
  }
  TREE.get_loop(n);
  for (int i = 1; i <= TREE.cnt_loop; ++i) {
    TREE.dfs1(TREE.loop[i], -1);
    TREE.dfs2(TREE.loop[i], -1, 1, TREE.loop[i], i, n);
  }
  for (int i = 1; i <= TREE.cnt_loop; ++i)
    dp1[i][0] = TREE.ans[i], dp2[i][0] = TREE.SZ[TREE.loop[i]];
  int LEN = TREE.cnt_loop;
  int ANS = 0;
  for (int len = 2; len <= LEN; ++len) {
    for (int i = 1; i <= LEN; ++i) {
      dp1[i][1] =
          max(dp1[realPos(i + 1, LEN)][0] + n - dp2[realPos(i + 1, LEN)][0] +
                  TREE.ele[TREE.loop[i]] - TREE.SZ[TREE.loop[i]],
              dp1[i][0] + n - dp2[i][0] +
                  TREE.ele[TREE.loop[realPos(i + len - 1, LEN)]] -
                  TREE.SZ[TREE.loop[realPos(i + len - 1, LEN)]]);
      dp2[i][1] = dp2[realPos(i + 1, LEN)][0] + TREE.SZ[TREE.loop[i]];
      if (len == LEN) ANS = max(ANS, dp1[i][1]);
    }
    for (int i = 1; i <= LEN; ++i) dp1[i][0] = dp1[i][1], dp2[i][0] = dp2[i][1];
  }
  printf("%d\n", ANS);
  return 0;
}
