Problem:
Score : 600 points

Problem Statement

We have a tree with N vertices. The i-th edge connects Vertex A_i and B_i bidirectionally.

Takahashi is standing at Vertex u, and Aoki is standing at Vertex v.

Now, they will play a game of tag as follows:

1. If Takahashi and Aoki are standing at the same vertex, the game ends. Otherwise, Takahashi moves to a vertex of his choice that is adjacent to his current vertex.

2. If Takahashi and Aoki are standing at the same vertex, the game ends. Otherwise, Aoki moves to a vertex of his choice that is adjacent to his current vertex.

3. Go back to step 1.

Takahashi performs his moves so that the game ends as late as possible, while Aoki performs his moves so that the game ends as early as possible.

Find the number of moves Aoki will perform before the end of the game if both Takahashi and Aoki know each other's position and strategy.

It can be proved that the game is bound to end.

Constraints

2 \leq N \leq 10^5

1 \leq u,v \leq N

u \neq v

1 \leq A_i,B_i \leq N

The given graph is a tree.

Input

Input is given from Standard Input in the following format:

N u v
A_1 B_1
:
A_{N-1} B_{N-1}

Output

Print the number of moves Aoki will perform before the end of the game.

Sample Input 1

5 4 1
1 2
2 3
3 4
3 5

Sample Output 1

2

If both players play optimally, the game will progress as follows:

Takahashi moves to Vertex 3.

Aoki moves to Vertex 2.

Takahashi moves to Vertex 5.

Aoki moves to Vertex 3.

Takahashi moves to Vertex 3.

Here, Aoki performs two moves.

Note that, in each move, it is prohibited to stay at the current vertex.

Sample Input 2

5 4 5
1 2
1 3
1 4
1 5

Sample Output 2

1

Sample Input 3

2 1 2
1 2

Sample Output 3

0

Sample Input 4

9 6 1
1 2
2 3
3 4
4 5
5 6
4 7
7 8
8 9

Sample Output 4

5

Solution in C# (Mono 4.6.2.0) (judge verdict: Wrong Answer)

using System;
using System.Linq;//リストの使用
using System.Collections.Generic;
using System.Text;//テキストの高速出力に必要
class Program
{
static long[] distanceMemos = new long[2];//キューから捨てた最短距離と頂点番号

  static void Main()
  {
    string[] input = Console.ReadLine().Split(' ');
    int n = int.Parse(input[0]);
    int u = int.Parse(input[1])-1;
    int v = int.Parse(input[2])-1;
    int answer = 0;

    int e = n-1;
    long[,] edges = new long[2*e,3];
    long[] answersU = new long[n];
    long[] answersV = new long[n];
    long[][] answersUV = new long[n][];

    for(int i = 0; i < n; i++)
    {
      answersUV[i] = new long[2];
    }

    for(long i = 0; i < e; i++)
    {
      long[] nums = Array.ConvertAll(Console.ReadLine().Split(' '),long.Parse);
      edges[2*i,0] = nums[0]-1;//有向辺でないなら2本必要
      edges[2*i,1] = nums[1]-1;
      edges[2*i,2] = 1;

      edges[2*i+1,0] = nums[1]-1;//有向辺でないなら2本必要
      edges[2*i+1,1] = nums[0]-1;
      edges[2*i+1,2] = 1;
    }
     
    answersU = Dijkstra(n,u,edges);
    answersV = Dijkstra(n,v,edges);
    for(int i = 0; i < n; i++)
    {
      answersUV[i][0] = answersU[i];
      answersUV[i][1] = answersV[i];
    }
    Array.Sort(answersUV, (a, b) => a[0].CompareTo(b[0]));
    
    for(int i = 0; i < n; i++)
    {
      if(answersUV[i][0] <= answersUV[i][1])
      {
        if((answersUV[i][1]-answersUV[i][0]) == 0)//同じ場所になる
        {
          answer =(int)Math.Max(answer, answersUV[i][1]);
          break;
        }
        else
          answer = (int)Math.Max(answer, answersUV[i][1]-1);
      }
    }
    Console.WriteLine(answer);
  }
 
  static long[] Dijkstra(int vertexCount, int startV, long[,] edges)
  {//ダイクストラ法により、O((|頂点数|+|辺数|)log頂点数)で各頂点への最短距離を求める
  //引数は頂点数、辺数、開始頂点(0-index)、辺の始点と終点と距離
  //返り値は各頂点までの最短距離、ただし到達できない場合は-1

    int n = vertexCount;
    int edgeCount = edges.GetLength(0);
    List<long[]>[] nextList = new List<long[]>[n];//頂点番号ごとの隣接リスト。距離、隣接頂点番号
    for(long i = 0; i < n; i++)
    {
      nextList[i] = new List<long[]>();//リストの宣言が必要
    }
    long[] colors = new long[n];//最短距離未確定の頂点が0、確定で2
    long[] distances = new long[n];//各頂点への最短距離

    for(long i = 0; i < edgeCount; i++)
    {
      long[] nextMemo = new long[2];
      nextMemo[1] = edges[i,1];//隣接頂点番号
      nextMemo[0] = edges[i,2];//距離
      nextList[edges[i,0]].Add(nextMemo);//隣接リストの作成
    }
  
    List<long[]> distanceList = new List<long[]>();//優先度付きキュー
    for(long i = 0; i < n; i++)
    {
      distances[i] = long.MaxValue;//最短距離を無限とおく
    }
 
    long[] newDistance = new long[2];
 
    //スタート地点を決める
    newDistance[1] = startV;//スタート地点番号
    distances[startV] = 0;
    colors[startV] = 1;
 
    newDistance[0] = 0;//スタートからスタートまでの距離0
    distanceList.Add(newDistance);
 
    while(distanceList.Count() != 0)
    {
      distanceList = PopHeap(distanceList);
      long minVertex = distanceMemos[1];//最短頂点の番号
      colors[minVertex] = 2;
      if(distances[minVertex] < distanceMemos[0]) continue;//最小値が最短でないなら無視
 
      for(long i = 0; i < nextList[minVertex].Count(); i++)
      {
        long v = nextList[minVertex][(int)i][1];
        if(colors[v] == 2) continue;
        if(distances[v] > distances[minVertex] + nextList[minVertex][(int)i][0])
        {
          distances[v] = distances[minVertex] + nextList[minVertex][(int)i][0];
          long[] newDistanceSub = new long[2];
          newDistanceSub[0] = distances[v];
          newDistanceSub[1] = v;
          distanceList = PushHeap(distanceList, newDistanceSub);
          colors[v] = 1;
        }
      }
    }

    for(long i = 0; i < n; i++)
    {
      if(distances[i] == long.MaxValue) distances[i] = -1;
        //全頂点について最短距離の出力。到達不可能な頂点は-1を出力。
    }
    return distances;
  }
 
  //引数は、昇順にソート済みのリスト
  static List<long[]> PushHeap(List<long[]> nums, long[] addNums)//現在のヒープnumsにaddNumを追加
  {
    int n = nums.Count;
    nums.Add(addNums);
 
    while (n > 0)
    {
      int i = (n-1)/2;
      if (nums[n][0] < nums[i][0])//親のほうが大きいなら入れ替え。
      {
        long tmp = nums[n][0];
        long tmpSub = nums[n][1];
        nums[n][0] = nums[i][0];
        nums[n][1] = nums[i][1];
        nums[i][0] = tmp;
        nums[i][1] = tmpSub;
      }
      n = i;
    }
    return nums;
  }
 
  static List<long[]> PopHeap(List<long[]> nums)//ヒープnumsからポップ
  {
    int n = nums.Count - 1;
    distanceMemos[0] = nums[0][0];//捨てる値の保存
    distanceMemos[1] = nums[0][1];
    nums[0][0] = nums[n][0];//最小値である根を削除してリストの最後を持ってくる
    nums[0][1] = nums[n][1];
    nums.RemoveAt(n);
 
    for (int i = 0, j; (j = 2*i+1) < n; )
    {
      if ((j != n-1) && (nums[j][0] > nums[j+1][0]))// ２つの子のうち、値の小さい方を選ぶ
        j++;
      if (nums[i][0] > nums[j][0])//子が親より小さいなら入れ替え
      {
        long tmp = nums[j][0];
        long tmpSub = nums[j][1];
        nums[j][0] = nums[i][0];
        nums[j][1] = nums[i][1];
        nums[i][0] = tmp;
        nums[i][1] = tmpSub;
      }
      i = j;
    }
    return nums;
  }
   
}