/**
 * Author: Sergey Kopeliovich (Burunduk30@gmail.com)
 * Date: 2015.03.02
 */

const int N = 1e5;

int n, x[N], d[N], p[N], size[N];
vector<int> c[N];
int T, t_in[N], t_out[N];
int cnt, no[N], pos[N], len[N], top[N];

struct SegmentTree {
  int n, *t;
  void build( int n ) {
    this->n = n, t = new int[2 * n]();
  }
  int getMax( int l, int r ) {
    int res = 0;
    for (l += n, r += n; l <= r; l >>= 1, r >>= 1) {
      if ((l & 1) == 1) res = max(res, t[l++]);
      if ((r & 1) == 0) res = max(res, t[r--]);
    }
    return res;
  }
  void change( int i, int x ) {
    t[i += n] = x;
    for (i >>= 1; i > 0; i >>= 1)
      t[i] = max(t[2 * i], t[2 * i + 1]);
  }
} s[N];

void dfs( int v, int pr, int dep = 0 ) {
  t_in[v] = T++;
  p[v] = pr, d[v] = dep, size[v] = 1;
  for (int x : c[v])
    if (x != pr)
      dfs(x, v, dep + 1), size[v] += size[x];
  t_out[v] = T++;
}

void calc( int v ) {
  if (v == p[v] || 2 * size[v] < size[p[v]])
    no[v] = cnt++, top[no[v]] = v;
  else
    no[v] = no[p[v]];
  pos[v] = len[no[v]]++;
  for (int x : c[v])
    if (x != p[v])
      calc(x);
}

int isAncestor( int a, int b ) {
  return t_in[a] <= t_in[b] && t_out[b] <= t_out[a];
}

int getMax( int a, int b ) {
  int res = INT_MIN, v;
  forn(t, 2) {
    while (!isAncestor(v = top[no[a]], b))
      res = max(res, s[no[a]].getMax(0, pos[a])), a = p[v];
    swap(a, b);
  }
  return max(res, s[no[a]].getMax(min(pos[a], pos[b]), max(pos[a], pos[b])));
}

void build() {
  dfs(0, 0);
  calc(0);
  forn(i, n)
    s[i].build(len[i]);
}