#include <bits/stdc++.h>
using namespace std;
typedef vector<int> vint;
typedef pair<int, int> pint;
#define CPP_STR(x) CPP_STR_I(x)
#define CPP_CAT(x, y) CPP_CAT_I(x, y)
#define CPP_STR_I(args...) #args
#define CPP_CAT_I(x, y) x##y
#define ASSERT(expr...) assert((expr))

/* type annotation */
using i8 = int8_t;
using u8 = uint8_t;
using i16 = int16_t;
using u16 = uint16_t;
using i32 = int32_t;
using u32 = uint32_t;
using i64 = int64_t;
using u64 = uint64_t;
using f32 = float;
using f64 = double;
constexpr i64 INF = 1'010'000'000'000'000'017LL;
constexpr i64 MOD = 1'000'000'007LL;
constexpr f64 EPS = 1e-12;
constexpr f64 PI = 3.14159265358979323846;

/* macros */
#define FOR(i, start, end)                             \
    for(i64 i = (start), CPP_CAT(i, xxxx_end) = (end); \
        i < CPP_CAT(i, xxxx_end); ++i)
#define rep(i, n) FOR(i, 0, n)
#define ALL(f, c, ...)                                               \
    (([&](decltype((c)) cccc) {                                      \
        return (f)(std::begin(cccc), std::end(cccc), ##__VA_ARGS__); \
    })(c))
template <typename C>
i64 SIZE(const C &c) {
    return static_cast<i64>(c.size());
}
template <typename T, size_t N>
i64 SIZE(const T (&)[N]) {
    return static_cast<i64>(N);
}
#define UNIQUE(v) v.erase(unique(v.begin(), v.end()), v.end())

struct IoSetup {
    IoSetup() {
        cin.tie(nullptr);
        ios::sync_with_stdio(false);
        // cout << fixed << setprecision(20);
        // cerr << fixed << setprecision(20);
    }
} iosetup;

/* keep a max,min */
template <typename T, typename U, typename Comp = less<>>
bool chmax(T &xmax, const U &x, Comp comp = {}) {
    if(comp(xmax, x)) {
        xmax = x;
        return true;
    }
    return false;
}

template <typename T, typename U, typename Comp = less<>>
bool chmin(T &xmin, const U &x, Comp comp = {}) {
    if(comp(x, xmin)) {
        xmin = x;
        return true;
    }
    return false;
}

/* input,output operator for pair, vector and map */

/* input,output operator for pair and vector */
template <typename T1, typename T2>
ostream &operator<<(ostream &os, const pair<T1, T2> &p) {
    os << p.first << " " << p.second;
    return os;
}

template <typename T1, typename T2>
istream &operator>>(istream &is, pair<T1, T2> &p) {
    is >> p.first >> p.second;
    return is;
}

template <typename T>
ostream &operator<<(ostream &os, const vector<T> &v) {
    for(int i = 0; i < (int)v.size(); i++) {
        os << v[i] << (i + 1 != v.size() ? " " : "");
    }
    return os;
}

template <typename T>
ostream &operator<<(ostream &os, const vector<vector<T>> &v) {
    for(int i = 0; i < (int)v.size(); i++) {
        os << v[i] << (i + 1 != v.size() ? "\n" : "");
    }
    return os;
}

template <typename T>
istream &operator>>(istream &is, vector<T> &v) {
    for(T &in : v) is >> in;
    return is;
}

template <typename T, typename U>
ostream &operator<<(ostream &os, const map<T, U> &mp) {
    os << "{";
    for(auto x = mp.begin(); x != mp.end(); ++x) {
        os << x->first << ":" << x->second << (x != prev(mp.end()) ? ", " : "");
    }
    os << "}";
    return os;
}

using std::to_string;

auto to_string(std::string s) -> std::string { return s; }

auto to_string(char c) -> std::string { return std::string{c}; }

auto to_string(const char *s) -> std::string {
    return to_string((std::string)s);
}

auto to_string(bool b) -> std::string { return (b ? "true" : "false"); }

template <typename T, typename U>
auto to_string(std::pair<T, U> p) -> std::string {
    return "(" + to_string(p.first) + ", " + to_string(p.second) + ")";
}

template <size_t N>
auto to_string(std::bitset<N> bs) -> std::string {
    std::string res{};
    for(size_t i = 0; i < N; i++)
        res.insert(res.begin(), bs.test(i) ? '1' : '0');
    return res;
}

template <typename T>
auto to_string(T v) -> std::string {
    bool flg = false;
    std::string res = "[";
    for(auto const &x : v) {
        if(flg)
            res += ", ";
        else
            flg = true;
        res += to_string(x);
    }
    res += "]";
    return res;
}

/* initialize vector. usage: auto v = make_v<int>(N,0); */
template <typename T>
vector<T> make_v(size_t a) {
    return vector<T>(a);
}

template <typename T, typename... Ts>
auto make_v(size_t a, Ts... ts) {
    return vector<decltype(make_v<T>(ts...))>(a, make_v<T>(ts...));
}

/* fill vector. usage: fill_v(v,0); */
template <typename T, typename V>
typename enable_if<is_class<T>::value == 0>::type fill_v(T &t, const V &v) {
    t = v;
}

template <typename T, typename V>
typename enable_if<is_class<T>::value != 0>::type fill_v(T &t, const V &v) {
    for(auto &e : t) fill_v(e, v);
}

namespace edamat {
template <class Info>
struct edge {
    int from, to;
    Info info;
    edge(int to, Info info) : to(to), info(info) {}
    edge(int from, int to, Info info) : from(from), to(to), info(info) {}
};

//! graphは基底クラス！使うときはundirected_graphかdirected_graphを使う。
template <class Info>
class graph {
   protected:
    using edge_type = edge<Info>;
    ::std::size_t N;
    ::std::vector<::std::vector<edge_type>> edges;

   public:
    graph(::std::size_t N_) : N(N_), edges(N_) {}
    virtual void add_edge(int x, int y, Info info = static_cast<Info>(1)) = 0;
    const ::std::vector<edge_type> &delta(int v) const {
        assert(v < N);
        return edges[v];
    }
    const ::std::vector<edge_type> &operator[](int v) const {
        return this->delta(v);
    }
    ::std::size_t size() const noexcept { return N; }
};

template <class Info>
struct rooted_tree : public graph<Info> {
    //    private:
    int l;
    int root = -1;
    ::std::vector<int> depth;
    ::std::vector<::std::vector<int>> par;

   public:
    rooted_tree(::std::size_t N) : graph<Info>(N), depth(N) {
        l = 0;
        while((1 << l) < N) l++;
        par =
            ::std::vector<::std::vector<int>>(l, ::std::vector<int>(N + 1, -1));
    }
    void add_edge(int x, int y, Info info = static_cast<Info>(1)) {
        this->edges[x].push_back(edge<Info>(x, y, info));
        this->edges[y].push_back(edge<Info>(y, x, info));
    }
    const int parent(int v) { return par[0][v]; }

    //    private:
    void dfs1(int v, int p = -1, int d = 0) {
        if(p != -1) par[0][v] = p;
        depth[v] = d;
        for(auto &e : this->edges[v]) {
            if(e.to == p) continue;
            dfs1(e.to, v, d + 1);
        }
    }
    ::std::pair<Info, int> dfs2(int v, int p) {
        ::std::pair<Info, int> ret(0, v);
        for(auto &e : this->edges[v]) {
            if(e.to == p) continue;
            auto cost = dfs2(e.to, v);
            cost.first += e.info;
            ret = max(ret, cost);
        }
        return ret;
    }

   public:
    void build(int _root = 0) {
        assert(root == -1);
        root = _root;
        dfs1(root, -1, 0);
        for(int i = 0; i < l - 1; ++i) {
            for(int j = 0; j < this->size(); j++) {
                if(par[i][j] == -1)
                    par[i + 1][j] = -1;
                else
                    par[i + 1][j] = par[i][par[i][j]];
            }
        }
    }
    int lca(int x, int y) {
        assert(root != -1);
        if(depth[x] > depth[y]) ::std::swap(x, y);
        int dif = depth[y] - depth[x];
        for(int i = l - 1; i >= 0; i--) {
            if(dif & (1 << i)) {
                y = par[i][y];
            }
        }
        if(x == y) return x;
        for(int i = l - 1; i >= 0; i--) {
            int nx = par[i][x], ny = par[i][y];
            if(nx != ny) {
                x = nx;
                y = ny;
            }
        }
        return par[0][x];
    }
    int depth_dif(int x, int y) {
        assert(root != -1);
        int z = lca(x, y);
        return depth[x] + depth[y] - 2 * depth[z];
    }
    const Info diameter() {
        auto p = dfs2(0, -1);
        auto q = dfs2(p.second, -1);
        return (q.first);
    }
};
}  // namespace edamat

void solve() {
    int n, u, v;
    scanf("%d%d%d", &n, &u, &v);
    u--;
    v--;
    edamat::rooted_tree<int> g(n);
    rep(i, n - 1) {
        int a, b;
        scanf("%d%d", &a, &b);
        a--, b--;
        g.add_edge(a, b);
    }
    g.build(v);
    auto d = g.depth_dif(u, v);
    auto d2 = g.dfs2(v, -1);
    auto d3 = g.lca(u, d2.second);
    if(g.depth_dif(d3, u) <= g.depth_dif(d3, v)) {
        std::cout << g.diameter() - 1 << std::endl;
    } else {
        if(d % 2 == 0) {
            std::cout << d / 2 << std::endl;
        } else {
            std::cout << (d + 1) / 2 << std::endl;
        }
    }
}
int main() {
    /* main code */
    solve();
    return 0;
}