#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using Pll = pair<ll, ll>;
using Pii = pair<int, int>;
constexpr ll MOD = 1000000007;
constexpr long double EPS = 1e-10;
constexpr int dyx[4][2] = {{0, 1}, {-1, 0}, {0, -1}, {1, 0}};
constexpr int N_MAX = 100000;
constexpr int INF = 1 << 30;
vector<int> graph[N_MAX];
template <class T>
class MinOp {
 public:
  T operator()(T a, T b) { return min(a, b); }
};
template <typename T, typename OpFunc>
struct SparseTable {
  OpFunc op;
  int size;
  vector<int> lg;
  vector<vector<T> > table;
  void init(const vector<T> &array, OpFunc opfunc) {
    int n = array.size();
    op = opfunc;
    lg.assign(n + 1, 0);
    for (int i = 1; i <= n; i++) {
      lg[i] = 31 - __builtin_clz(i);
    }
    table.assign(lg[n] + 1, array);
    for (int i = 1; i <= lg[n]; i++) {
      for (int j = 0; j < n; j++) {
        if (j + (1 << (i - 1)) < n) {
          table[i][j] = op(table[i - 1][j], table[i - 1][j + (1 << (i - 1))]);
        } else {
          table[i][j] = table[i - 1][j];
        }
      }
    }
  }
  T query(int l, int r) {
    assert(l < r);
    return op(table[lg[r - l]][l], table[lg[r - l]][r - (1 << lg[r - l])]);
  }
};
struct PMORMQ {
  vector<int> a;
  SparseTable<pair<int, int>, MinOp<pair<int, int> > > sparse_table;
  vector<vector<vector<int> > > lookup_table;
  vector<int> block_type;
  int block_size, n_block;
  void init(const vector<int> &array) {
    a = array;
    int n = a.size();
    block_size = max(1, (31 - __builtin_clz(n)) / 2);
    while (n % block_size != 0) {
      a.push_back(a.back() + 1);
      n++;
    }
    n_block = n / block_size;
    vector<pair<int, int> > b(n_block, make_pair(INT_MAX, INT_MAX));
    for (int i = 0; i < n; i++) {
      b[i / block_size] = min(b[i / block_size], make_pair(a[i], i));
    }
    sparse_table.init(b, MinOp<pair<int, int> >());
    block_type.assign(n_block, 0);
    for (int i = 0; i < n_block; i++) {
      int cur = 0;
      for (int j = 0; j < block_size - 1; j++) {
        int ind = i * block_size + j;
        if (a[ind] < a[ind + 1]) {
          cur |= 1 << j;
        }
      }
      block_type[i] = cur;
    }
    lookup_table.assign(
        1 << (block_size - 1),
        vector<vector<int> >(block_size, vector<int>(block_size + 1)));
    for (int i = 0; i < (1 << (block_size - 1)); i++) {
      for (int j = 0; j < block_size; j++) {
        int res = 0;
        int cur = 0;
        int pos = j;
        for (int k = j + 1; k <= block_size; k++) {
          lookup_table[i][j][k] = pos;
          if (i & (1 << (k - 1))) {
            cur++;
          } else {
            cur--;
          }
          if (res > cur) {
            pos = k;
            res = cur;
          }
        }
      }
    }
  }
  int query(int l, int r) {
    assert(l < r);
    int lb = l / block_size;
    int rb = r / block_size;
    if (lb == rb) {
      return lb * block_size +
             lookup_table[block_type[lb]][l % block_size][r % block_size];
    }
    int pl = lb * block_size +
             lookup_table[block_type[lb]][l % block_size][block_size];
    int pr = rb * block_size + lookup_table[block_type[rb]][0][r % block_size];
    int pos = pl;
    if (r % block_size > 0 && a[pl] > a[pr]) {
      pos = pr;
    }
    if (lb + 1 == rb) {
      return pos;
    }
    int sp = sparse_table.query(lb + 1, rb).second;
    if (a[pos] > a[sp]) {
      return sp;
    }
    return pos;
  }
};
struct LCA {
  int n;
  vector<vector<int> > G;
  PMORMQ rmq;
  int cnt;
  vector<int> depth, id, in;
  void init(int size) {
    n = size;
    G.assign(n, vector<int>(0));
  }
  void add_edge(int a, int b) {
    G[a].push_back(b);
    G[b].push_back(a);
  }
  void dfs(int x, int p, int d) {
    id[cnt] = x;
    depth.push_back(d);
    in[x] = cnt++;
    for (int v : G[x]) {
      if (v == p) {
        continue;
      }
      dfs(v, x, d + 1);
      id[cnt] = x;
      depth.push_back(d);
      cnt++;
    }
  }
  void precalc(int root) {
    cnt = 0;
    depth.clear();
    in.assign(n, -1);
    id.assign(2 * n - 1, -1);
    dfs(root, -1, 0);
    rmq.init(depth);
  }
  int lca(int a, int b) {
    int x = in[a];
    int y = in[b];
    if (x > y) {
      swap(x, y);
    }
    int pos = rmq.query(x, y + 1);
    return id[pos];
  }
};
LCA lca;
vector<ll> dist(N_MAX, INF);
void dfs(int node, int par, int d) {
  dist[node] = d;
  for (int child : graph[node]) {
    if (par == child) continue;
    if (dist[child] != INF) continue;
    dfs(child, node, d + 1);
  }
}
ll get_dist(int a, int b) {
  return dist[a] + dist[b] - 2 * dist[lca.lca(a, b)];
}
int minimax(int takahashi, int aoki, bool takahashi_turn, int aoki_cnt) {
  if (takahashi == aoki) {
    return aoki_cnt;
  }
  if (takahashi_turn) {
    int max_aoki_cnt = -1, argmax_node = -1;
    for (int next_node : graph[takahashi]) {
      int child_ret = minimax(next_node, aoki, false, aoki_cnt);
      if (max_aoki_cnt < child_ret) {
        max_aoki_cnt = child_ret;
        argmax_node = next_node;
      }
    }
    return max_aoki_cnt;
  } else {
    int min_aoki_cnt = 1 << 30, argmin_node = -1;
    for (int next_node : graph[aoki]) {
      if (get_dist(takahashi, aoki) < get_dist(takahashi, next_node)) continue;
      int child_ret = minimax(takahashi, next_node, true, aoki_cnt + 1);
      if (min_aoki_cnt > child_ret) {
        min_aoki_cnt = child_ret;
        argmin_node = next_node;
      }
      return min_aoki_cnt;
    }
    return min_aoki_cnt;
  }
}
int main() {
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  int n, takahashi, aoki, a, b;
  cin >> n >> takahashi >> aoki;
  lca.init(n);
  --takahashi;
  --aoki;
  for (int i = 0; i < n - 1; ++i) {
    cin >> a >> b;
    --a;
    --b;
    graph[a].push_back(b);
    graph[b].push_back(a);
    lca.add_edge(a, b);
  }
  lca.precalc(0);
  dfs(0, -1, 0);
  cout << minimax(takahashi, aoki, true, 0) << endl;
}
