#include <bits/stdc++.h>
using namespace std;
using lint = long long int;
using pint = pair<int, int>;
using plint = pair<lint, lint>;
struct fast_ios {
  fast_ios() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    cout << fixed << setprecision(20);
  };
} fast_ios_;
template <typename T>
istream &operator>>(istream &is, vector<T> &vec) {
  for (auto &v : vec) is >> v;
  return is;
}
template <typename T>
ostream &operator<<(ostream &os, const vector<T> &vec) {
  os << "[";
  for (auto v : vec) os << v << ",";
  os << "]";
  return os;
}
template <typename T>
ostream &operator<<(ostream &os, const deque<T> &vec) {
  os << "deq[";
  for (auto v : vec) os << v << ",";
  os << "]";
  return os;
}
template <typename T>
ostream &operator<<(ostream &os, const set<T> &vec) {
  os << "{";
  for (auto v : vec) os << v << ",";
  os << "}";
  return os;
}
template <typename T>
ostream &operator<<(ostream &os, const unordered_set<T> &vec) {
  os << "{";
  for (auto v : vec) os << v << ",";
  os << "}";
  return os;
}
template <typename T>
ostream &operator<<(ostream &os, const multiset<T> &vec) {
  os << "{";
  for (auto v : vec) os << v << ",";
  os << "}";
  return os;
}
template <typename T>
ostream &operator<<(ostream &os, const unordered_multiset<T> &vec) {
  os << "{";
  for (auto v : vec) os << v << ",";
  os << "}";
  return os;
}
template <typename T1, typename T2>
ostream &operator<<(ostream &os, const pair<T1, T2> &pa) {
  os << "(" << pa.first << "," << pa.second << ")";
  return os;
}
template <typename TK, typename TV>
ostream &operator<<(ostream &os, const map<TK, TV> &mp) {
  os << "{";
  for (auto v : mp) os << v.first << "=>" << v.second << ",";
  os << "}";
  return os;
}
template <typename TK, typename TV>
ostream &operator<<(ostream &os, const unordered_map<TK, TV> &mp) {
  os << "{";
  for (auto v : mp) os << v.first << "=>" << v.second << ",";
  os << "}";
  return os;
}
template <typename T>
void ndarray(vector<T> &vec, int len) {
  vec.resize(len);
}
template <typename T, typename... Args>
void ndarray(vector<T> &vec, int len, Args... args) {
  vec.resize(len);
  for (auto &v : vec) ndarray(v, args...);
}
template <typename T>
bool mmax(T &m, const T q) {
  if (m < q) {
    m = q;
    return true;
  } else
    return false;
}
template <typename T>
bool mmin(T &m, const T q) {
  if (m > q) {
    m = q;
    return true;
  } else
    return false;
}
template <typename T1, typename T2>
pair<T1, T2> operator+(const pair<T1, T2> &l, const pair<T1, T2> &r) {
  return make_pair(l.first + r.first, l.second + r.second);
}
template <typename T1, typename T2>
pair<T1, T2> operator-(const pair<T1, T2> &l, const pair<T1, T2> &r) {
  return make_pair(l.first - r.first, l.second - r.second);
}
class UndirectedWeightedTree {
  using T = long long int;
  const int INVALID = -1;
  int V, lgV;
  int E;
  int root;
  vector<vector<pair<int, int>>> adj;
  vector<T> weight;
  vector<int> par;
  vector<int> depth;
  vector<T> acc_weight;
  void _fix_root_dfs(int now, int prv, int prv_edge_id) {
    par[now] = prv;
    if (prv_edge_id != INVALID)
      acc_weight[now] = acc_weight[prv] + weight[prv_edge_id];
    for (auto nxt : adj[now])
      if (nxt.first != prv) {
        depth[nxt.first] = depth[now] + 1;
        _fix_root_dfs(nxt.first, now, nxt.second);
      }
  }

 public:
  UndirectedWeightedTree(int N = 0) : V(N), E(0), adj(N) {
    lgV = 1;
    while (1 << lgV < V) lgV++;
  }
  void add_edge(int u, int v, T w) {
    adj[u].emplace_back(v, E);
    adj[v].emplace_back(u, E);
    weight.emplace_back(w);
    E++;
  }
  void fix_root(int r) {
    root = r;
    par.resize(V);
    depth.assign(V, 0);
    acc_weight.resize(V);
    _fix_root_dfs(root, INVALID, INVALID);
  }
  vector<vector<int>> doubling;
  void doubling_precalc() {
    doubling.assign(lgV, vector<int>(V));
    doubling[0] = par;
    for (int d = 0; d < lgV - 1; d++)
      for (int i = 0; i < V; i++) {
        if (doubling[d][i] == INVALID)
          doubling[d + 1][i] = INVALID;
        else
          doubling[d + 1][i] = doubling[d][doubling[d][i]];
      }
  }
  int kth_parent(int x, int k) {
    for (int d = 0; d < lgV; d++) {
      if (x == INVALID) return INVALID;
      if (k & (1 << d)) x = doubling[d][x];
    }
    return x;
  }
  int lowest_common_ancestor(int u, int v) {
    if (depth[u] > depth[v]) swap(u, v);
    v = kth_parent(v, depth[v] - depth[u]);
    if (u == v) return u;
    for (int d = lgV - 1; d >= 0; d--) {
      if (doubling[d][u] != doubling[d][v])
        u = doubling[d][u], v = doubling[d][v];
    }
    return par[u];
  }
  T path_length(int u, int v) {
    int r = lowest_common_ancestor(u, v);
    return (acc_weight[u] - acc_weight[r]) + (acc_weight[v] - acc_weight[r]);
  }
};
int main() {
  int N, u, v;
  cin >> N >> u >> v;
  u--, v--;
  UndirectedWeightedTree t(N);
  for (int _ = (0), __end_ = (N - 1); _ < __end_; _++) {
    int a, b;
    cin >> a >> b;
    t.add_edge(a - 1, b - 1, 1);
  }
  t.fix_root(v);
  t.doubling_precalc();
  int d = t.path_length(u, v);
  int ret = d / 2 - (d % 2 == 0);
  u = t.kth_parent(u, ret);
  v = t.kth_parent(u, d - ret);
  int nokori = 0;
  for (int i = (0), i_end_ = (N); i < i_end_; i++)
    if (i != u and i != v) {
      int lu = t.path_length(i, u);
      int lv = t.path_length(i, v);
      if (lu < lv) mmax(nokori, lu);
    }
  ret += nokori + (d % 2 == 0);
  cout << ret << endl;
}
