#include <bits/stdc++.h>
using namespace std;
using LL = long long;
template <typename T>
inline T& unused_var(T& v) {
  return v;
}
struct cww {
  cww() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout << fixed;
    cout << setprecision(10);
  }
};
cww star;
template <typename T>
std::istream& operator>>(std::istream& is, std::vector<T>& v) {
  for (auto& it : v) is >> it;
  return is;
}
class reverse_range {
 private:
  struct I {
    int x;
    int operator*() { return x - 1; }
    bool operator!=(I& lhs) { return x > lhs.x; }
    void operator++() { --x; }
  };
  I i, n;

 public:
  reverse_range(int n) : i({0}), n({n}) {}
  reverse_range(int i, int n) : i({i}), n({n}) {}
  I& begin() { return n; }
  I& end() { return i; }
};
class range {
 private:
  struct I {
    int x;
    int operator*() { return x; }
    bool operator!=(I& lhs) { return x < lhs.x; }
    void operator++() { ++x; }
  };
  I i, n;

 public:
  range(int n) : i({0}), n({n}) {}
  range(int i, int n) : i({i}), n({n}) {}
  I& begin() { return i; }
  I& end() { return n; }
  reverse_range operator!() { return reverse_range(*i, *n); }
};
template <typename T>
struct min_op {
  static T exec(const T l, const T r) { return l < r ? l : r; }
};
template <typename T>
struct max_op {
  static T exec(const T l, const T r) { return l > r ? l : r; }
};
template <typename F, typename T>
inline T multi_op(T&& v) {
  return v;
}
template <typename F, typename T, typename... Ts>
inline T multi_op(const T head, Ts&&... tail) {
  return F::exec(head, multi_op<F>(tail...));
}
template <typename T, typename... Ts>
inline T multi_min(T&& head, Ts&&... tail) {
  return multi_op<min_op<T> >(head, tail...);
}
template <typename T, typename... Ts>
inline T multi_max(T&& head, Ts&&... tail) {
  return multi_op<max_op<T> >(head, tail...);
}
template <typename F, typename T, typename... Ts>
inline bool ch_op(T& target, Ts&&... candidates) {
  const T old = target;
  target = multi_op<F>(target, candidates...);
  return old != target;
}
template <typename T, typename... Ts>
inline bool chmin(T& target, Ts&&... candidates) {
  return ch_op<min_op<T> >(target, candidates...);
}
template <typename T, typename... Ts>
inline bool chmax(T& target, Ts&&... candidates) {
  return ch_op<max_op<T> >(target, candidates...);
}
const pid_t pid = getpid();
class XorShift32 {
 private:
  unsigned value;
  inline void update() {
    value = value ^ (value << 13);
    value = value ^ (value >> 17);
    value = value ^ (value << 5);
  }
  inline unsigned get() {
    unsigned v = value;
    update();
    return v;
  }

 public:
  template <int bit = 31>
  inline int next_int() {
    return (int)(get() >> (32 - bit));
  }
  template <int bit = 31>
  inline int next_signed() {
    unsigned v = get();
    return (int)((v >> (31 - bit)) - (1 << (bit)));
  }
  template <int bit = 31>
  inline int range_max() {
    return (int)((1u << bit) - 1);
  };
  XorShift32(const unsigned seed) {
    value = seed;
    update();
  }
  XorShift32() : XorShift32(pid) {}
};
struct Edge {
  int id;
  int a;
  int b;
  Edge(int id = 0, int a = 0, int b = 0) : id(id), a(a), b(b) {}
  inline int versus(const int v) const { return a ^ b ^ v; }
};
template <typename COST_TYPE>
struct WeightedEdge {
  int id;
  int a;
  int b;
  COST_TYPE cost;
  WeightedEdge(int id = 0, int a = 0, int b = 0, int cost = 0)
      : id(id), a(a), b(b), cost(cost) {}
  inline int versus(const int v) const { return a ^ b ^ v; }
};
template <typename E = Edge>
class Graph {
 private:
  std::vector<E> edges;
  std::vector<std::vector<int> > g;

 public:
  Graph(int reserved_vertex_size = 1, int reserved_edge_size = -1) {
    g.reserve(reserved_vertex_size);
    edges.reserve(std::max(reserved_vertex_size, reserved_edge_size));
  }
  inline int size() { return g.size(); }
  inline int degree(const int v) { return g[v].size(); }
  inline int degree() { return edges.size(); }
  inline void resize(const int n) { g.resize(n); }
  template <typename... Ts>
  inline void add_edge(int a, int b, Ts&&... params) {
    const int id = edges.size();
    if ((int)g.size() <= std::max(a, b)) {
      g.resize(std::max(a, b) + 1);
    }
    g[a].emplace_back(id);
    g[b].emplace_back(id);
    edges.emplace_back(id, a, b, std::forward<Ts>(params)...);
  }
  inline void add_edge(E e) {
    e.id = edges.size();
    if ((int)g.size() <= max(e.a, e.b)) {
      g.resize(max(e.a, e.b) + 1);
    }
    g[e.a].emplace_back(e.id);
    g[e.b].emplace_back(e.id);
    edges.emplace_back(e);
  }
  template <typename... Ts>
  inline void add_arc(int a, int b, Ts&&... params) {
    const int id = edges.size();
    if ((int)g.size() <= std::max(a, b)) {
      g.resize(std::max(a, b) + 1);
    }
    g[a].emplace_back(id);
    edges.emplace_back(id, a, b, std::forward<Ts>(params)...);
  }
  inline void add_arc(E e) {
    e.id = edges.size();
    if ((int)g.size() <= std::max(e.a, e.b)) {
      g.resize(std::max(e.a, e.b) + 1);
    }
    g[e.a].emplace_back(e.id);
    edges.emplace_back(e);
  }
  inline std::vector<int> Ns(const int v) {
    std::vector<int> ns(g[v].size());
    for (int i = 0; i < degree(v); i++) {
      ns[i] = edges[g[v][i]].versus(v);
    }
    return ns;
  }
  inline const std::vector<int>& operator[](const int v) { return g[v]; }
  inline E& i2e(const int edge_id) { return edges[edge_id]; }
};
template <typename E = Edge>
class Forest : public Graph<E> {
 private:
  using Graph<E>::add_edge;
  std::vector<int> roots;
  void build_tree(Graph<E>& g, const int v, std::vector<bool>& used) {
    used[v] = true;
    for (int edge_id : g[v]) {
      auto e = g.i2e(edge_id);
      const int u = e.versus(v);
      if (used[u]) continue;
      e.a = v;
      e.b = u;
      this->add_arc(e);
      build_tree(g, u, used);
    }
  }

 public:
  Forest(Graph<E>& g, const int loop_begin_vtx = 0)
      : Graph<E>(g.size(), g.size() - 1) {
    this->resize(g.size());
    std::vector<bool> used(g.size());
    for (int v : range(loop_begin_vtx, g.size() + loop_begin_vtx)) {
      v = v % g.size();
      if (used[v] == false) {
        build_tree(g, v, used);
        roots.push_back(v);
      }
    }
  }
  std::vector<int> get_roots() { return roots; }
};
template <typename E = Edge>
class Tree : public Forest<E> {
 private:
  using Forest<E>::get_roots;
  const int root;

 public:
  Tree(Graph<E>& g, const int root = 0) : Forest<E>(g, root), root(root) {}
  inline int get_root() { return root; }
};
template <typename T>
class BufferManager {
 protected:
  T* buf;

 public:
  BufferManager(T* buf) : buf(buf) {}
  virtual T* pop(int size) = 0;
  virtual void push(T* p) = 0;
  virtual void clear() = 0;
};
template <typename T>
class DisposableBufferManager : public BufferManager<T> {
 private:
  int ptr;

 public:
  DisposableBufferManager(T* buf) : BufferManager<T>(buf), ptr(0){};
  T* pop(int size) {
    ptr += size;
    return this->buf + ptr - size;
  }
  void push(T* p) { unused_var(p); }
  void clear() { ptr = 0; }
  int get_ptr() { return ptr; }
};
template <typename T>
class BlockBufferManager : public BufferManager<T> {
 private:
  std::queue<T*> que;

 public:
  BlockBufferManager(T* buf, int blocks, int block_size)
      : BufferManager<T>(buf) {
    for (int i : range(blocks)) {
      que.push(this->buf + i * block_size);
    }
  };
  T* pop(int size = 0) {
    unused_var(size);
    T* ptr = que.front();
    que.pop();
    return ptr;
  }
  void push(T* p) { que.push(p); }
  void clear() {}
  int get_queue_size() { return que.size(); }
};
int ret = 0;
int par[212345];
void dfs0(int v, Tree<>& t, int p) {
  par[v] = p;
  for (int u : t.Ns(v)) {
    dfs0(u, t, v);
  }
}
void dfs1(int v, Tree<>& t, vector<int>& ok) {
  for (int u : t.Ns(v)) {
    if (ok[v] == 0) ok[u] = 0;
    dfs1(u, t, ok);
  }
}
void dfs2(int v, Tree<>& t, vector<int>& ok, int d = 0) {
  if (ok[v] && t.degree(v) != 0) {
    chmax(ret, d);
  }
  for (int u : t.Ns(v)) {
    dfs2(u, t, ok, d + 1);
  }
}
int main() {
  int N, D, O;
  cin >> N >> D >> O;
  O--;
  D--;
  Graph<> g(N, N);
  for (int i : range(N - 1)) {
    int a, b;
    cin >> a >> b;
    g.add_edge(a - 1, b - 1);
  }
  vector<int> ok(N, 1);
  {
    Tree<> t(g, D);
    dfs0(t.get_root(), t, t.get_root());
    int len = 0;
    {
      int z = O;
      while (z != D) {
        z = par[z];
        len++;
        cerr << z << endl;
      }
    }
    {
      int z = O;
      int i = 0;
      while (z != D && i < len / 2) {
        ok[z] = 0;
        z = par[z];
        i++;
      }
    }
    dfs1(t.get_root(), t, ok);
  }
  {
    Tree<> t(g, O);
    dfs2(t.get_root(), t, ok);
  }
  cout << ret << endl;
  return 0;
}
