Problem:
Score : 800 points

Problem Statement

Takahashi and Aoki will play a game on a tree.
The tree has N vertices numbered 1 to N, and the i-th of the N-1 edges connects Vertex a_i and Vertex b_i.

At the beginning of the game, each vertex contains a coin.
Starting from Takahashi, he and Aoki will alternately perform the following operation:

Choose a vertex v that contains one or more coins, and remove all the coins from v.

Then, move each coin remaining on the tree to the vertex that is nearest to v among the adjacent vertices of the coin's current vertex.

The player who becomes unable to play, loses the game.
That is, the player who takes his turn when there is no coin remaining on the tree, loses the game.
Determine the winner of the game when both players play optimally.

Constraints

1 \leq N \leq 2 \times 10^5

1 \leq a_i, b_i \leq N

a_i \neq b_i

The graph given as input is a tree.

Input

Input is given from Standard Input in the following format:

N
a_1 b_1
a_2 b_2
:
a_{N-1} b_{N-1}

Output

Print First if Takahashi will win, and print Second if Aoki will win.

Sample Input 1

3
1 2
2 3

Sample Output 1

First

Here is one possible progress of the game:

Takahashi removes the coin from Vertex 1. Now, Vertex 1 and Vertex 2 contain one coin each.

Aoki removes the coin from Vertex 2. Now, Vertex 2 contains one coin.

Takahashi removes the coin from Vertex 2. Now, there is no coin remaining on the tree.

Aoki takes his turn when there is no coin on the tree and loses.

Sample Input 2

6
1 2
2 3
2 4
4 6
5 6

Sample Output 2

Second

Sample Input 3

7
1 7
7 4
3 4
7 5
6 3
2 1

Sample Output 3

First

Solution in C# (Mono 4.6.2.0) (judge verdict: Accepted)

using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using SB = System.Text.StringBuilder;
//using System.Threading.Tasks;
//using System.Text.RegularExpressions;
//using System.Globalization;
//using System.Diagnostics;
using static System.Console;
using System.Numerics;
using static System.Math;
using pair = Pair<int, int>;

class Program
{
    static void Main()
    {
        //SetOut(new StreamWriter(OpenStandardOutput()) { AutoFlush = false });
        new Program().solve();
        Out.Flush();
    }
    readonly Scanner cin = new Scanner();
    readonly int[] dd = { 0, 1, 0, -1, 0 }; //→↓←↑
    readonly int mod = 1000000007;
    readonly int dom = 998244353;
    bool chmax<T>(ref T a, T b) where T : IComparable<T> { if (a.CompareTo(b) < 0) { a = b; return true; } return false; }
    bool chmin<T>(ref T a, T b) where T : IComparable<T> { if (b.CompareTo(a) < 0) { a = b; return true; } return false; }

    void solve()
    {
        int N = cin.nextint;
        var D = new Dijkstra();
        var E = D.Input(N, N - 1);
        var dist = D.Run(E, 0);
        int id = -1;
        long max = -1;
        for (int i = 0; i < dist.Length; i++)
        {
            if (chmax(ref max, dist[i]))
            {
                id = i;
            }
        }
        dist = D.Run(E, id);
        max = -1;
        for (int i = 0; i < dist.Length; i++)
        {
            chmax(ref max, dist[i]);
        }
        if ((max + 2) % 3 == 0)
        {
            WriteLine("Second");
        }
        else
        {
            WriteLine("First");
        }
    }

}

class Dijkstra
{
    public readonly long Inf;
    public Dijkstra(long Inf = long.MaxValue / 2) { this.Inf = Inf; }

    /// <summary>
    /// VertexとEdgeを兼ねる
    /// </summary>
    public struct Edge : IComparable<Edge>
    {
        public int to; public long cost;
        public Edge(int to, long cost)
        {
            this.to = to;
            this.cost = cost;
        }
        public int CompareTo(Edge e) => cost.CompareTo(e.cost);
    }
    /// <summary>
    /// Dijkstraな入力を行う
    /// </summary>
    /// <param name="n">頂点数</param>
    /// <param name="m">辺数</param>
    /// <param name="dir">有向/無向 デフォルト: 無向</param>
    /// <param name="indexed">indexedの補正 デフォルト: 1</param>
    /// <returns></returns>
    public List<Edge>[] Input(int n, int m, bool dir = false, int indexed = 1, bool cost = true)
    {
        Scanner cin = new Scanner();
        var ret = new List<Edge>[n];
        for (int i = 0; i < n; i++)
        {
            ret[i] = new List<Edge>();
        }
        for (int i = 0; i < m; i++)
        {
            int a = cin.nextint - indexed;
            int b = cin.nextint - indexed;
            var c = 1;
            ret[a].Add(new Edge(b, c));
            if (!dir) ret[b].Add(new Edge(a, c));
        }
        return ret;
    }
    public long[] Run(List<Edge>[] edges, int s)
    {
        int n = edges.Length;
        var dist = new long[n];
        var Q = new PriorityQueue<Edge>(-1);
        for (int i = 0; i < n; i++) dist[i] = Inf;
        dist[s] = 0;
        Q.Enqueue(new Edge(s, dist[s]));
        while (Q.Any())
        {
            var p = Q.Dequeue();
            var v = p.to;
            if (dist[v] < p.cost) continue;
            foreach (var e in edges[v])
            {
                var d = p.cost + e.cost;
                if (d < dist[e.to])
                {
                    dist[e.to] = d;
                    Q.Enqueue(new Edge(e.to, d));
                }
            }
        }
        return dist;
    }
    /// <summary>
    /// 最短路 経路総数 Modとり
    /// </summary>
    /// <param name="edges"></param>
    /// <param name="s"></param>
    /// <param name="cnt"></param>
    /// <param name="Mod"></param>
    /// <returns></returns>
    public long[] Run(List<Edge>[] edges, int s, out long[] cnt, long Mod)
    {
        int n = edges.Length;
        var dist = new long[n];
        var Q = new PriorityQueue<Edge>(-1);
        for (int i = 0; i < n; i++) dist[i] = Inf;
        dist[s] = 0;
        Q.Enqueue(new Edge(s, dist[s]));
        cnt = new long[n];
        cnt[s] = 1;
        while (Q.Any())
        {
            var p = Q.Dequeue();
            var v = p.to;
            if (dist[v] < p.cost) continue;
            foreach (var e in edges[v])
            {
                var d = p.cost + e.cost;
                if (d < dist[e.to])
                {
                    dist[e.to] = d;
                    cnt[e.to] = cnt[p.to];
                    Q.Enqueue(new Edge(e.to, d));
                }
                else if (d == dist[e.to])
                {
                    cnt[e.to] = (cnt[e.to] + cnt[p.to]) % Mod;
                }
            }
        }
        return dist;
    }
}
/// <summary>
/// Original Author: 蟻本
/// </summary>
/// <typeparam name="T"></typeparam>
class PriorityQueue<T> where T : IComparable<T>
{
    List<T> heap;
    readonly int cmp;
    public PriorityQueue(int cmp = 1) { heap = new List<T>(); this.cmp = cmp; }
    public void Enqueue(T x)
    {
        heap.Add(x);
        int i = Count++;
        while (i > 0)
        {
            int p = (i - 1) >> 1;
            if (x.CompareTo(heap[p]) * cmp <= 0) break;
            heap[i] = heap[p]; i = p;
        }
        heap[i] = x;
    }
    public T Dequeue()
    {
        T ret = heap[0]; T x = heap[--Count];
        int i = 0;
        while ((i << 1) + 1 < Count)
        {
            int a = (i << 1) + 1; int b = (i << 1) + 2;
            if (b < Count && heap[a].CompareTo(heap[b]) * cmp < 0) a = b;
            if (x.CompareTo(heap[a]) * cmp >= 0) break;
            heap[i] = heap[a]; i = a;
        }
        heap[i] = x; heap.RemoveAt(Count);
        return ret;
    }
    public int Count { get; private set; }
    public bool Any() => Count > 0;
    public T Peek() => heap[0];
}


static class Ex
{
    public static void join<T>(this IEnumerable<T> values, string sep = " ") => WriteLine(string.Join(sep, values));
    public static string concat<T>(this IEnumerable<T> values) => string.Concat(values);
    public static string reverse(this string s) { var t = s.ToCharArray(); Array.Reverse(t); return t.concat(); }

    public static int lower_bound<T>(this IList<T> arr, T val) where T : IComparable<T>
    {
        int low = 0, high = arr.Count;
        int mid;
        while (low < high)
        {
            mid = ((high - low) >> 1) + low;
            if (arr[mid].CompareTo(val) < 0) low = mid + 1;
            else high = mid;
        }
        return low;
    }
    public static int upper_bound<T>(this IList<T> arr, T val) where T : IComparable<T>
    {
        int low = 0, high = arr.Count;
        int mid;
        while (low < high)
        {
            mid = ((high - low) >> 1) + low;
            if (arr[mid].CompareTo(val) <= 0) low = mid + 1;
            else high = mid;
        }
        return low;
    }
}

class Pair<T, U> : IComparable<Pair<T, U>> where T : IComparable<T> where U : IComparable<U>
{
    public T f; public U s;
    public Pair(T f, U s) { this.f = f; this.s = s; }
    public int CompareTo(Pair<T, U> a) => f.CompareTo(a.f) != 0 ? f.CompareTo(a.f) : s.CompareTo(a.s);
    public override string ToString() => $"{f} {s}";
}

class Scanner
{
    string[] s; int i;
    readonly char[] cs = new char[] { ' ' };
    public Scanner() { s = new string[0]; i = 0; }
    public string[] scan => ReadLine().Split();
    public int[] scanint => Array.ConvertAll(scan, int.Parse);
    public long[] scanlong => Array.ConvertAll(scan, long.Parse);
    public double[] scandouble => Array.ConvertAll(scan, double.Parse);
    public string next
    {
        get
        {
            if (i < s.Length) return s[i++];
            string st = ReadLine();
            while (st == "") st = ReadLine();
            s = st.Split(cs, StringSplitOptions.RemoveEmptyEntries);
            i = 0;
            return next;
        }
    }
    public int nextint => int.Parse(next);
    public long nextlong => long.Parse(next);
    public double nextdouble => double.Parse(next);
}