#ifndef ENV_AC
    #define ENV_AC
    #include <stdio.h>
    #include <stdlib.h>
    #include <assert.h>
    #include <fstream>
    #include <iostream>
    #include <sstream>
    #include <iomanip>
    #include <algorithm>
    #include <bitset>
    #include <array>
    #include <vector>
    #include <queue>
    #include <set>
    #include <cmath> // 変数名にy1が使えなくなるかも…。
    #include <map>
    #include <unordered_map>
    #include <unordered_set>
    #include <limits>
    #include <functional>
    #include <string>
    #include <ext/rope>

    using int128_t = __int128_t;
    std::istream &operator>>(std::istream& input, int128_t& value) { // int128_tの入力。入力が64bitに収まる前提。
        int64_t tmp; input >> tmp; value = tmp;
        return input;
    }
    std::ostream &operator<<(std::ostream& output, const int128_t value) { // int128_tの出力。出力が64bitに収まる前提。
        output << (int64_t)value;
        return output;
    }

    namespace std {
        template<> class hash<int128_t>{
            public:
            size_t operator () ( const int128_t &x ) const {
                int64_t INF64 = std::numeric_limits<int64_t>::max();
                int64_t y1 = x / INF64;
                int64_t y2 = x % INF64;
                return hash<int64_t>()(y1) ^ hash<int64_t>()(y2);
            }
        };
    }

    int128_t imax(const int128_t a, const int128_t b) { return std::max(a, b); } // std::max, std::min は型が違うとエラーになるため、ラッパーを作る。
    int128_t imin(const int128_t a, const int128_t b) { return std::min(a, b); }
    int128_t iabs(const int128_t x) { return 0 <= x ? x : -x; }
    int128_t ipow(const int128_t x, const int128_t n) { int128_t ret = 1; for (int i = 0; i < n; i++) { ret *= x; } return ret; } // 1 << d みたいな書き方は、dが32以上だと困るので、ipow(2,d)を使う。

    // xを任意の整数とし、0 < m としたとき、x = pm + r の形式でxを表す。ただし0 <= r < m とする。xが負の時に少し処理を要する。
    std::pair<int128_t, int128_t> divmod(int128_t x, int128_t m) {
        assert(0 < m);
        if (0 <= x % m) {
            return std::pair<int128_t, int128_t>({x / m, x % m});
        } else {
            return std::pair<int128_t, int128_t>({x / m - 1, x % m + m});
        }
    }

    template <int128_t mod> class Mod_Int {
        public:
        int128_t val;

        void calc() {
            if (val < 0) { val += ((iabs(val) + mod) / mod) * mod; }
            val %= mod;
        }
        Mod_Int(const int128_t _val = 0) { val = _val; calc(); }
        int128_t INT() { return val; } // 使用は非想定
        int128_t MOD() { return mod; } // 使用は非想定
        Mod_Int operator-() const { return Mod_Int(-val); }
        Mod_Int operator+(const Mod_Int &r) const { return Mod_Int(val + r.val); }
        Mod_Int operator-(const Mod_Int &r) const { return Mod_Int(val - r.val); }
        Mod_Int operator*(const Mod_Int &r) const { return Mod_Int(val * r.val); }
        //Mod_Int operator/(const Mod_Int &r) const { return ; } // ユークリッド互除法を使うべきだが保留。
        Mod_Int& operator+=(const Mod_Int &r) { val += r.val; calc(); return *this; }
        Mod_Int& operator-=(const Mod_Int &r) { val -= r.val; calc(); return *this; }
        Mod_Int& operator*=(const Mod_Int &r) { val *= r.val; calc(); return *this; }
        Mod_Int& operator++() { return (*this) += 1; }
        Mod_Int& operator--() { return (*this) -= 1; }
        Mod_Int operator++(int) { Mod_Int tmp = *this; ++*this; return tmp; }
        Mod_Int operator--(int) { Mod_Int tmp = *this; --*this; return tmp; }
        bool operator==(const Mod_Int &r) const { return val == r.val; }
        bool operator!=(const Mod_Int &r) const { return val != r.val; }

        friend std::istream &operator>>(std::istream& input, Mod_Int& r) { 
            int128_t tmp; input >> tmp;
            r = Mod_Int(tmp);
            return input;
        }
        friend std::ostream &operator<<(std::ostream& output, const Mod_Int& r) { 
            output << r.val;
            return output;
        }
    };

    struct Closed_Section {
        bool valid;
        int128_t begin;
        int128_t end;
        Closed_Section(bool _valid, int128_t _begin, int128_t _end) {
            valid = _valid; begin = _begin; end = _end;
        }
        Closed_Section() {
            valid = false, begin = 0; end = -1;
        }
        int128_t size() { return valid ? end - begin + 1 : 0; }
        Closed_Section operator*(const Closed_Section &r) const {
            if (!valid) { return Closed_Section(valid, begin, end); }
            if (!r.valid) { return r; }
            if (end < r.begin) { return Closed_Section(false, 0, -1); }
            if (r.end < begin) { return Closed_Section(false, 0, -1); }
            return Closed_Section(true, std::max(begin, r.begin), std::min(end, r.end));
        }
        void dump() { std::cout << "valid:" << valid << " begin:" << begin << " end:" << end << std::endl; }
    };

    //template<class Fn> Closed_Section binary_search(int128_t L, int128_t R, Fn func) {
    Closed_Section binary_search(const int128_t L, const int128_t R, std::function<bool(int128_t)> func) {
        if (R < L) { return Closed_Section(false, L, R); }
        const bool res_L = func(L);
        const bool res_R = func(R);
        if (res_L && res_R) {
            return Closed_Section(true, L, R);
        } else if (!res_L && !res_R) {
            return Closed_Section(false, 0, -1);
        } else {
            int128_t lb = L;
            int128_t ub = R;
            while (lb + 1 < ub) {
                int128_t mid = (lb + ub) / 2;
                if (res_L == func(mid)) {
                    lb = mid;
                } else {
                    ub = mid;
                }
            }
            return res_L ? Closed_Section(true, L, lb) : Closed_Section(true, ub, R);
        }
    }

    Closed_Section binary_search(const Closed_Section& cs, std::function<bool(int128_t)> func) {
        return cs.valid ? binary_search(cs.begin, cs.end, func) : cs;
    }

    #define rep(i, begin, end) for(int64_t i = ((int128_t)begin); i <= ((int128_t)end); i++) // (int128_t)end としておくと、end = v.size() - 2 みたいな入力で、v.size()が1でも正常(end = -1になる）に挙動する。end = 2 - v.size() - 1のような入力でも、int128_tであれば計算がint128_tで進行する（intやint64_tだと途中でsize_tになってしまう。）。
    #define rev(i, begin, end) for(int64_t i = ((int128_t)begin); ((int128_t)end) <= i; i--) // int128_tにすると、3重ループでコンパイルエラーになることがあった（再現性は不明）ので変数はint64_tにしておく。

    #define input1(begin, end, v1) v1.resize((end)+1); for (int itr = (begin); itr <= (end); itr++) { std::cin >> v1[itr]; }
    #define input2(begin, end, v1, v2) v1.resize((end)+1); v2.resize((end)+1); for (int itr = (begin); itr <= (end); itr++) { std::cin >> v1[itr] >> v2[itr]; } 
    #define input3(begin, end, v1, v2, v3) v1.resize((end)+1); v2.resize((end)+1); v3.resize((end)+1); for (int itr = (begin); itr <= (end); itr++) { std::cin >> v1[itr] >> v2[itr] >> v3[itr]; }
    #define input4(begin, end, v1, v2, v3, v4) v1.resize((end)+1); v2.resize((end)+1); v3.resize((end)+1); v4.resize((end)+1); for (int i = (begin); i <= (end); i++) { std::cin >> v1[i] >> v2[i] >> v3[i] >> v4[i]; } 
    #define input5(begin, end, v1, v2, v3, v4, v5) v1.resize((end)+1); v2.resize((end)+1); v3.resize((end)+1); v4.resize((end)+1); v5.resize((end)+1); for (int i = (begin); i <= (end); i++) { std::cin >> v1[i] >> v2[i] >> v3[i] >> v4[i] >> v5[i]; }  
    // input_arrayはbegin = 0のときのみ動作確認。Aの要素の型をテンプレートにして関数にしたほうが丁寧かもしれない。
    #define input_array(begin, N, M, A) A.resize((begin)+(N)); for (int i = 0; i < (begin)+(N); i++) { A[i].resize((begin)+(M)); } for (int i = begin; i < (begin)+(N); i++) { for (int j = begin; j < (begin)+(M); j++) { std::cin >> A[i][j]; }}

    std::vector<int128_t> irange(const int128_t begin, const int128_t end) {
        std::vector<int128_t> ret; for (int128_t i = begin; i <= end; i++) { ret.push_back(i); }
        return ret;
    }

    template <typename T>
    std::vector<T> accumulate_vec(const std::vector<T>& vec, const bool reverse = false) {
        std::vector<T> ret; ret.resize(vec.size());
        if (0 < vec.size()) {
            if (reverse == false) {
                ret[0] = vec[0];
                for (int i = 1; i < ret.size(); i++) {
                    ret[i] = ret[i-1] + vec[i];
                }
            } else {
                ret[ret.size()-1] = vec[ret.size()-1];
                for (int i = ret.size() - 2; 0 <= i; i--) {
                    ret[i] = ret[i+1] + vec[i];
                }
            }
        }
        return ret;
    }

    template <typename T>
    void sort_vec(
        std::vector<T>& vec, int128_t begin, int128_t end, 
        std::function<bool(T, T)> func = [&](const T& a, const T& b) { return a < b; }
    ) {
        std::sort(vec.begin() + begin, vec.begin() + end + 1, func);
    }

    template <typename T>
    T cal_pow(T x, int128_t n, T tmp = T(1)) {
        // 累乗の計算。
        while (n > 0) {
            if (n & 1) { tmp = tmp * x; }
            x = x * x;
            n = (n >> 1);
        }
        return tmp;
    }

    std::vector<int128_t> digit(int128_t n, const int128_t b) {
        // 基数bでの表示。0は0桁。非常に大きい数を入れても問題ないようにint128_tとする。
        // size()をとれば桁数になる。
        assert(1 < b);
        std::vector<int128_t> ret;
        while (0 < n) {
            ret.push_back(n % b);
            n /= b;
        }
        return ret;
    }

    template <typename T>
    void printvec(const std::vector<T>& vec) {
        for (int i = 0; i < vec.size(); i++) { std::cout << vec[i] << " "; } std::cout << std::endl;
    }
#endif

// 木のクラス。
// 有向グラフと同様に表現する。
// （Tipsに含まれている関数で、こちらに移植していないものがあるので注意。get_children）
struct Tree_New {
    struct Edge { 
        int to; int64_t cost;
    };
    typedef std::vector<std::vector<Edge>> adj_list;
    adj_list G;
    int node_num;
    Tree_New() {}
    Tree_New(const int node_num_in) {
        node_num = node_num_in;
        G.resize(node_num);
    }
    void add_directed_edge(const int from, const int to, const long long cost) {
        Edge edge; edge.to = to; edge.cost = cost;
        G[from].push_back(edge);
    }
    void add_undirected_edge(const int node1, const int node2, const long long cost) {
        add_directed_edge(node1, node2, cost);
        add_directed_edge(node2, node1, cost);
    }
    // ret[i][t] := i->t の辺がG[i]の何番目にあるか。全方位木DPをやるときに使いやすい。
    std::vector<std::unordered_map<int, int>> edge_map() const {
        std::vector<std::unordered_map<int, int>> ret; ret.resize(G.size());
        for (int i = 0; i < G.size(); i++) {
            for (int j = 0; j < G[i].size(); j++) {
                ret[i][G[i][j].to] = j;
            }
        }
        return ret;
    }
    // 木の直径。（最長パス）。木は無向（逆辺が同じ重みで必ず存在）で、重みは全て正の想定。
    int128_t diameter() const {
        std::vector<std::unordered_map<int, int>> emp = edge_map();
        std::vector<std::vector<std::vector<int128_t>>> memo[3];
        for (int m = 0; m < 3; m++) {
            memo[m].resize(G.size());
            for (int i = 0; i < G.size(); i++) {
                memo[m][i].resize(G[i].size());
            }
        }
        std::function<std::vector<int128_t>(int, int, int)> dfs = [&] (int mode, int parent, int eid) {
            if (eid == -1 || eid == G[parent].size()) { return std::vector<int128_t>({0, 0}); }
            if (!memo[(mode + 3) % 3][parent][eid].empty()) { return memo[(mode + 3) % 3][parent][eid]; }
            if (mode != 0) {
                std::vector<int128_t> ret = dfs(mode, parent, eid + mode);
                ret.push_back(dfs(0, parent, eid)[0]);
                std::sort(ret.begin(), ret.end(), std::greater<int128_t>());
                ret.resize(2);
                return memo[(mode + 3) % 3][parent][eid] = ret;
            } else {
                int node = G[parent][eid].to;
                int r = emp[node][parent];
                return memo[(mode + 3) % 3][parent][eid] = std::vector<int128_t>({std::max(dfs(-1, node, r - 1)[0], dfs(1, node, r + 1)[0]) + G[parent][eid].cost});
            }
        };
        int128_t ret = 0;
        for (int i = 0; i < G.size(); i++) {
            std::vector<int128_t> tmp = dfs(1, i, 0);
            ret = std::max(ret, tmp[0] + tmp[1]);
        }
        return ret;
    }
    std::vector<int> cal_rank(const int root) { // root を根としたときのrankを計算する。costとは無関係である。
        assert(root < node_num);
        std::vector<int> rank; rank.resize(node_num, -1);
        std::function<void(int, int, int)> dfs = [&] (int n, int r, int parent) {
            rank[n] = r;
            for (Edge e : G[n]) {
                if (e.to != parent) {
                    dfs(e.to, r + 1, n);
                }
            }
        };
        dfs(root, 0, -1);
        return rank;
    }
    std::vector<int> rank_descending_ids(const int root, const int begin, const int end) { // root を根としたときに、rankの降順にノード番号を並べる。
        assert(begin <= root && root <= end);
        assert(end < node_num);
        std::vector<int> rank = cal_rank(root);
        std::vector<int> ret;
        for (int i = begin; i <= end; i++) {
            ret.push_back(i);
        }
        std::sort(ret.begin(), ret.end(), [&](const int i, const int j) {
            return rank[i] > rank[j];
        });
        return ret;
    }
    std::vector<int> cal_partial_size(const int root) {
        // root を根としたとして各頂点を根とした部分木のサイズを求める。
        assert(root < node_num);
        std::vector<int> ret; ret.resize(node_num, 0);
        std::function<void(int, int)> dfs = [&] (int n, int parent) {
            for (Edge e : G[n]) {
                if (e.to != parent) {
                    dfs(e.to, n);
                    ret[n] += ret[e.to];
                }
            }
            ret[n] += 1;
        };
        dfs(root, -1);
        return ret;
    }

    std::vector<int> cal_parent(const int root) { // root を根としたときの親を計算する。有向木では行うまでもない。rootの親はrootとしておく。
        assert(root < node_num);
        std::vector<int> ret; ret.resize(node_num, -1);
        std::function<void(int, int)> dfs = [&] (int n, int p) {
            ret[n] = p;
            for (Edge e : G[n]) {
                if (e.to != p) {
                    dfs(e.to, n);
                }
            }
        };
        dfs(root, root);
        return ret;
    }
    std::vector<std::vector<int>> cal_parent_doubling(const int root) {
        // parentのダブリング構築。ret[i][n]は、nから2^iだけ親の方へ進んだ節点になる。
        std::vector<std::vector<int>> ret;
        std::vector<int> parent = cal_parent(root);
        ret.push_back(parent);
        while (true) {
            std::vector<int> pd; pd.resize(node_num);
            bool end_flag = true;
            for (int i = 0; i < node_num; i++) {
                if (ret.back()[i] == root || ret.back()[i] == -1) {
                    pd[i] = ret.back()[i];
                } else {
                    pd[i] = ret.back()[ret.back()[i]];
                    if (pd[i] != root) { 
                        end_flag = false;
                    }
                }
            }
            ret.push_back(pd);
            if (end_flag) { break; }
        }
        return ret;
    }
    int cal_ancestor(int node, int num, const std::vector<std::vector<int>>& parent_doubling) {
        // parent_doublingを利用して、nodeからnumだけ根の方向に進んだノードを求める。
        for (int i = 0; 0 < num; i++) {
            if (num % 2 == 1) {
                node = parent_doubling[i][node];
            }
            num /= 2;
        }
        return node;
    }
    int lca(int u, int v, const std::vector<int>& rank, const std::vector<std::vector<int>>& parent_doubling) {
        // rank と parent_doublingから、least common ancestorを計算。
        if (rank[u] < rank[v]) {
            v = cal_ancestor(v, rank[v] - rank[u], parent_doubling);
        } else {
            u = cal_ancestor(u, rank[u] - rank[v], parent_doubling);
        }
        assert(rank[v] == rank[u]);
        if (u == v) { return u; }
        int lb = 0; int ub = rank[u];
        while (lb + 1 < ub) {
            int mid = (lb + ub) / 2;
            if (cal_ancestor(u, mid, parent_doubling) == cal_ancestor(v, mid, parent_doubling)) {
                ub = mid;
            } else {
                lb = mid;
            }
        }
        return cal_ancestor(u, ub, parent_doubling);
    }

    void dfs_in_order_child(int n, int parent, std::vector<std::pair<int, int>>& order) {
        order.push_back({parent, n});
        for (Edge e : G[n]) {
            if (e.to != parent) {
                dfs_in_order_child(e.to, n, order);
            }
        }
        order.push_back({n, parent});
    } 
    std::vector<std::pair<int, int>> dfs_in_order(const int root) { 
        // root を根としたdfsで、通りがけ順に辺を並べる。オイラーツアーというらしい。
        // 全ての辺が、子に向かう方向と根に向かう方向でそれぞれ1度カウントされるので、サイズは(N-1)*2となる。
        assert(root < node_num);
        std::vector<std::pair<int, int>> order;
        for (Edge e : G[root]) {
            dfs_in_order_child(e.to, root, order);
        }
        return order;
    }
};


//--code begin--
 
int128_t N, u, v;
std::vector<int128_t> A, B;
//std::string S;
//std::vector<std::string> ;
//double A, B, H, W;
//std::vector<double> ;

//const int128_t MAX_N = 6;
const int128_t MAX_N = 1e5 + 10;
//const int128_t MOD = ;
//const int128_t INF = std::numeric_limits<int64_t>::max(); const int128_t NEG_INF = std::numeric_limits<int64_t>::min();
//using pair = std::pair<int128_t, int128_t>;
//using mnt = Mod_Int<MOD>;

Tree_New tree(MAX_N);
 
int main(int argc, char **argv) {
    std::cin.tie(0);
   	std::ios::sync_with_stdio(false);
    std::cout << std::fixed << std::setprecision(15);
 
    std::cin >> N >> u >> v;
    input2(1, N-1, A, B);

    rep (i, 1, N-1) {
        tree.add_undirected_edge(A[i], B[i], 1);
    }

    auto du = tree.cal_rank(u);
    auto dv = tree.cal_rank(v);

    std::vector<int128_t> end;
    int128_t dist = 0;
    rep (i, 1, N) {
        if (du[i] < dv[i]) {
            if (dist < dv[i]) {
                end.clear();
                end.push_back(i);
                dist = dv[i];
            } else if (dist == dv[i]) {
                end.push_back(i);
            }
        }
    }
    std::cout << dist - 1 << std::endl;

    /*
    //printvec(end);
    int128_t ret = 0;
    for (int128_t x : end) {

    }
    */
    
    return 0;
 
}

Measured memory_bytes: 18304