package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
)

type graph struct {
	N    int     // 頂点数
	es   []int   // 経路探索における各頂点の探索優先順位（重み付け）
	edge [][]int // 各頂点と隣接する他頂点の情報を保持する
}

// setEdge は頂点A,B間の経路情報を元にグラフを形成する
func (g *graph) setEdge(N int, M int, A []int, B []int) {

	g.N = N
	g.es = make([]int, N)
	g.edge = make([][]int, N)
	for i := 0; i < N; i++ {
		g.edge[i] = make([]int, N*2)
	}

	// 各頂点における他頂点との接続数をカウントし、各頂点の最大コスト初期値とする
	for i := 0; i < M; i++ {
		g.es[A[i]]++
		g.es[B[i]]++
	}
	for i := 0; i < M; i++ {
		// 頂点Aから頂点Bへの経路を保持する
		g.edge[A[i]][g.es[A[i]]] = B[i]
		g.es[A[i]]++ // 重み付け。隣接頂点が多い頂点ほど、経路探索では後回しにする
		// 頂点Bから頂点Aへの経路を保持する
		g.edge[B[i]][g.es[B[i]]] = A[i]
		g.es[B[i]]++ // 重み付け。隣接頂点が多い頂点ほど、経路探索では後回しにする
	}
}

// getDist は頂点rootから各頂点までの最短経路をダイクストラ法で求めresに格納する
func (g *graph) getDist(root int, res []int) {

	// rootから各頂点までの初期コストを無限遠点の代用として-1で初期化する
	for i := 0; i < g.N; i++ {
		res[i] = -1
	}
	// 頂点root自身への到達コストは0なので、同値で初期化する
	res[root] = 0

	s := 0 // 調査済頂点数、最初は未調査で始まるので0

	// 調査対象の頂点を保持するキュー
	q := make([]int, g.N)
	// 最初の起点はrootなので、キューの頭に同頂点を登録する
	q[0] = root

	for z := 1; z != 0; { // z:要コスト調査頂点数が0になるまで繰り返す

		i := q[s] // 今回調査の起点とする頂点を取得する
		s++       // 調査済の頂点数をカウントアップ
		z--       // 未調査の頂点数をカウントダウン

		for j := 0; j < g.es[i]; j++ { // 隣接頂点について、同頂点と他の接続数が少ない順に見ていく
			k := g.edge[i][j] // 隣接頂点を得る
			if res[k] >= 0 {  // 同頂点までのコストが調査済の場合はパスする
				continue
			}
			// 頂点間のコストは1固定なので、現頂点までのコストに1加えた値を
			// 隣接頂点kまでのコストとして設定する
			res[k] = res[i] + 1
			// 次にコスト調査の起点とする頂点を調査対象キューに突っ込む
			q[s+z] = k
			// 要コスト調査頂点数をカウントアップ
			z++
		}
	}
}

func main() {
	// 2≤N≤10^5
	N := readint()
	// 1≤u,v≤N
	// u≠v
	u := readint() - 1
	v := readint() - 1
	// 1≤Ai,Bi≤N
	A := make([]int, N-1)
	B := make([]int, N-1)
	for i := 0; i < N-1; i++ {
		A[i] = readint() - 1
		B[i] = readint() - 1
	}
	// 同じ頂点で始まる場合、青木君が移動する回数は0で終了する
	if u == v {
		fmt.Println(0)
		return
	}

	// u:高橋君が先に動く。逃げる方（青木君と同じ頂点ならその場で終了、先に動く）
	// v:青木君が後に動く。追い詰める方（高橋君と同じ頂点ならその場で終了、後で動く）

	// 経路探索の為のグラフを形成する
	var g graph
	g.setEdge(N, N-1, A, B)

	// 高橋君から見た各頂点への最短到達コストを求める
	d1 := make([]int, 100000)
	g.getDist(u, d1)

	// 青木君から見た角頂点への最短到達コストを求める
	d2 := make([]int, 100000)
	g.getDist(v, d2)

	// 逃げる高橋君から見た、追う青木君の出発点の距離を半分にしたものを移動回数の
	// 最小値として設定する。両出発点からそれぞれが合流する為に移動した場合の最小
	// 移動回数である。（現在の葉から他の葉に移るより先に合流してしまうケース）
	ans := d1[v] / 2

	// しかし高橋君は当然長引かせる方向で逃げるので、より遠い距離の頂点があれば
	// そこまで頑張って逃げる。
	for i := 0; i < N; i++ { // 各頂点において、
		if d1[i] < d2[i] { // 同頂点への到達コストがd1:逃げる側＜d2:追う側で
			// 現在の最大コストより同頂点までの到達コストが高くなるようであれば、
			// そちらに切り替える。
			ans = max(ans, d2[i]-1)
		}
	}
	fmt.Println(ans)
}

const (
	iobufsize = 1 * 1024 * 1024 // 1 MB
)

var stdinsc = func() *bufio.Scanner {
	sc := bufio.NewScanner(os.Stdin)
	sc.Buffer(make([]byte, iobufsize), iobufsize)
	sc.Split(bufio.ScanWords)
	return sc
}()

func readint() int {
	stdinsc.Scan()
	v, err := strconv.Atoi(stdinsc.Text())
	if err != nil {
		panic(err)
	}
	return v
}

func readstr() string {
	stdinsc.Scan()
	return stdinsc.Text()
}

func pow(x, y int) int {
	if y < 1 {
		return 1
	}
	return x * pow(x, y-1)
}

func min(x, y int) int {
	if x < y {
		return x
	}
	return y
}

func max(x, y int) int {
	if x > y {
		return x
	}
	return y
}
