Submission #2737847


Source Code Expand

import java.io.*;
import java.util.*;

/**
 * @author baito
 */
class UnionFindTree
{
    int[] par;
    int[] rank;
    int[] sizes;

    UnionFindTree(int n)
    {
        par = new int[n];
        rank = new int[n];
        sizes = new int[n];
        for (int i = 0; i < n; i++)
        {
            par[i] = i;
            sizes[i] = 1;
        }
    }

    int root(int x)
    {
        if (par[x] == x) return x;
        else return par[x] = root(par[x]);
    }

    void unite(int x, int y)
    {
        x = root(x);
        y = root(y);

        if (x == y) return;
        if (rank[x] < rank[y])
        {
            par[x] = y;
            sizes[y] += sizes[x];
        }
        else
        {
            par[y] = x;
            sizes[x] += sizes[y];
            if (rank[x] == rank[y]) rank[x]++;
        }
    }

    boolean isSame(int x, int y)
    {
        return root(x) == root(y);
    }

    int size(int x)
    {
        return sizes[par[x]];
    }
}

public class Main
{
    static StringBuilder sb = new StringBuilder();
    static FastScanner sc = new FastScanner(System.in);
    static int INF = 12345678;
    static long LINF = 123456789123456789L;
    static long MINF = -123456789123456789L;
    static long MOD = 1000000007;
    static int[] y4 = {0, 1, 0, -1};
    static int[] x4 = {1, 0, -1, 0};
    static int[] y8 = {0, 1, 0, -1, -1, 1, 1, -1};
    static int[] x8 = {1, 0, -1, 0, 1, -1, 1, -1};
    static long[] F;//factorial
    static boolean[] isPrime;
    static int[] primes;
    static char[][] map;

    static int N, M;
    static int[] A;


    public static void main(String[] args)
    {
        N = sc.nextInt();
        int[] a = new int[N - 1];
        int[] b = new int[N - 1];
        sc.nextIntArrays2arDec(a, b);
        Dijkstra d = new Dijkstra(0, N);
        for (int i = 0; i < N - 1; i++)
        {
            d.addEdge(a[i], b[i], 1);
            d.addEdge(b[i], a[i], 1);
        }
        long[] dis = d.solve();
        long toGoalDis = dis[N - 1];
        List<Integer> path = d.getShotestPath(N - 1);

        int midIndex = (int) Math.ceil((toGoalDis - 1) * 1.0 / 2);
        int boundaryf = path.get(midIndex);
        int boundarys = path.get(midIndex + 1);

        UnionFindTree uni = new UnionFindTree(N);
        for (int i = 0; i < N - 1; i++)
        {
            if (a[i] == boundaryf && b[i] == boundarys) continue;
            if (a[i] == boundarys && b[i] == boundaryf) continue;
            uni.unite(a[i], b[i]);
        }
        if (uni.size(0) > uni.size(N - 1))
        {
            System.out.println("Fennec");
        }
        else
        {
            System.out.println("Snuke");
        }

    }

    static class Dijkstra
    {
        long initValue = LINF;
        Node[] nodes;
        int s, n;
        long[] d;
        int prev[]; //最短経路の直前の頂点 -1ならnull

        Dijkstra(int s, int n)
        {
            this.s = s;
            this.n = n;
            nodes = new Node[n];
            for (int i = 0; i < n; i++)
                nodes[i] = new Node(i);
            d = new long[n];
            //todo 現状最短経路が複数ある場合に対応できていない
            //todo prev = List<LinkedList>();として複数の直前最短頂点を持とう
            prev = new int[n];
            Arrays.fill(d, initValue);
            Arrays.fill(prev, -1);
            d[s] = 0;
        }

        Dijkstra(int s, int n, int edge, boolean isDirectedGraph)
        {
            this.s = s;
            this.n = n;

            nodes = new Node[n];
            for (int i = 0; i < n; i++)
                nodes[i] = new Node(i);

            d = new long[n];
            prev = new int[n];
            Arrays.fill(d, initValue);
            Arrays.fill(prev, -1);
            d[s] = 0;

            if (isDirectedGraph)
            {
                for (int ei = 0; ei < edge; ei++)
                {
                    int f = sc.nextInt() - 1;
                    int t = sc.nextInt() - 1;
                    long c = 1;
                    addEdge(f, t, c);
                }
            }
            else
            {
                for (int ei = 0; ei < edge; ei++)
                {
                    int f = sc.nextInt() - 1;
                    int t = sc.nextInt() - 1;
                    long c = 1;
                    addEdge(f, t, c);
                    addEdge(t, f, c);
                }
            }
        }

        void addEdge(int f, int t, long c)
        {
            nodes[f].edges.add(new Edge(t, c));
        }

        long[] solve()
        {
            //頂点とそこへの最短距離を持つ
            PriorityQueue<Dis> q = new PriorityQueue<>();
            q.add(new Dis(s, 0));
            while (!q.isEmpty())
            {
                Dis now = q.poll();
                int nowId = now.p;
                long nowC = now.cos;
                for (Edge edge : nodes[nowId].edges)
                {
                    int to = edge.toId;
                    long needsCost = edge.toCost + nowC;
                    if (d[to] == initValue || needsCost < d[to])
                    {
                        d[to] = needsCost;
                        prev[to] = nowId;
                        q.add(new Dis(to, needsCost));
                    }
                }
            }
            return d;
        }

        //O( E ^ 2) 辺が密の時用
        long[] solve2()
        {
            boolean[] used = new boolean[n];
            long[][] cost = new long[n][n];
            Main.fill(cost, initValue);

            for (Node node : nodes)
            {
                for (Edge edge : node.edges)
                {
                    int fromId = node.id;
                    int toId = edge.toId;
                    long toCost = edge.toCost;
                    cost[fromId][toId] = toCost;
                }
            }
            while (true)
            {
                int v = -1;
                //まだ使われていない頂点のうち、距離が最小のものを探す。
                for (int u = 0; u < n; u++)
                    if (!used[u] && (v == -1 || d[u] < d[v])) v = u;
                if (v == -1) break;
                used[v] = true;
                for (int u = 0; u < n; u++)
                {
                    if (d[u] > d[v] + cost[v][u])
                    {
                        d[u] = d[v] + cost[v][u];
                        prev[u] = v;
                    }
                }
            }
            return d;
        }

        List<Integer> getShotestPath(int to)
        {
            List<Integer> path = new LinkedList<>();
            int now = to;
            while (true)
            {
                path.add(now);
                now = prev[now];
                if (now == -1) break;
            }
            Collections.reverse(path);
            return path;
        }

        static class Dis implements Comparable<Dis>
        {
            //現在地点 最短距離
            int p;
            long cos;

            Dis(int p, long cost)
            {
                this.p = p;
                cos = cost;
            }

            public int compareTo(Dis d)
            {
                if (cos != d.cos)
                {
                    if (cos > d.cos) return 1;
                    else if (cos == d.cos) return 0;
                    else return -1;
                }
                else
                {
                    return p - d.p;
                }
            }
        }

        static class Node
        {
            int id;
            List<Edge> edges;

            Node(int id)
            {
                edges = new ArrayList<>();
                this.id = id;
            }
        }

        static class Edge
        {
            int toId;
            long toCost;

            Edge(int id, long cost)
            {
                toId = id;
                toCost = cost;
            }

        }
    }


    public static boolean isOutofIndex(int x, int y)
    {
        if (x < 0 || y < 0) return true;
        if (map[0].length <= x || map.length <= y) return true;
        return false;
    }

    public static void setPrimes()
    {
        int n = 100001;
        isPrime = new boolean[n];
        List<Integer> prs = new ArrayList<>();
        Arrays.fill(isPrime, true);
        isPrime[0] = isPrime[1] = false;
        for (int i = 2; i * i <= n; i++)
        {
            if (!isPrime[i]) continue;
            prs.add(i);
            for (int j = i * 2; j < n; j += i)
            {
                isPrime[j] = false;
            }
        }
        primes = new int[prs.size()];
        for (int i = 0; i < prs.size(); i++)
            primes[i] = prs.get(i);
    }

    public static void revSort(int[] a)
    {
        Arrays.sort(a);
        reverse(a);
    }

    public static void revSort(long[] a)
    {
        Arrays.sort(a);
        reverse(a);
    }

    public static int[][] copy(int[][] ar)
    {
        int[][] nr = new int[ar.length][ar[0].length];
        for (int i = 0; i < ar.length; i++)
            for (int j = 0; j < ar[0].length; j++)
                nr[i][j] = ar[i][j];
        return nr;
    }

    public static long sumMod(long... lar)
    {
        long sum = 0;
        for (long l : lar)
            sum = (sum + l % MOD) % MOD;
        return sum;
    }

    /**
     * <h1>指定した値以上の先頭のインデクスを返す</h1>
     * <p>配列要素が0のときは、0が返る。</p>
     *
     * @return<b>int</b> : 探索した値以上で、先頭になるインデクス
     */
    public static int lowerBound(final int[] arr, final int value)
    {
        int low = 0;
        int high = arr.length;
        int mid;
        while (low < high)
        {
            mid = ((high - low) >>> 1) + low;    //(low + high) / 2 (オーバーフロー対策)
            if (arr[mid] < value)
            {
                low = mid + 1;
            }
            else
            {
                high = mid;
            }
        }
        return low;
    }

    /**
     * <h1>指定した値より大きい先頭のインデクスを返す</h1>
     * <p>配列要素が0のときは、0が返る。</p>
     *
     * @return<b>int</b> : 探索した値より上で、先頭になるインデクス
     */
    public static int upperBound(final int[] arr, final int value)
    {
        int low = 0;
        int high = arr.length;
        int mid;
        while (low < high)
        {
            mid = ((high - low) >>> 1) + low;    //(low + high) / 2 (オーバーフロー対策)
            if (arr[mid] <= value)
            {
                low = mid + 1;
            }
            else
            {
                high = mid;
            }
        }
        return low;
    }

    //次の順列に書き換える、最大値ならfalseを返す
    public static boolean nextPermutation(int A[])
    {
        int len = A.length;
        int pos = len - 2;
        for (; pos >= 0; pos--)
        {
            if (A[pos] < A[pos + 1]) break;
        }
        if (pos == -1) return false;

        //posより大きい最小の数を二分探索
        int ok = pos + 1;
        int ng = len;
        while (Math.abs(ng - ok) > 1)
        {
            int mid = (ok + ng) / 2;
            if (A[mid] > A[pos]) ok = mid;
            else ng = mid;

        }

        swap(A, pos, ok);
        reverse(A, pos + 1, len - 1);


        return true;
    }

    //次の順列に書き換える、最小値ならfalseを返す
    public static boolean prevPermutation(int A[])
    {
        int len = A.length;
        int pos = len - 2;
        for (; pos >= 0; pos--)
        {
            if (A[pos] > A[pos + 1]) break;
        }
        if (pos == -1) return false;

        //posより小さい最大の数を二分探索
        int ok = pos + 1;
        int ng = len;
        while (Math.abs(ng - ok) > 1)
        {
            int mid = (ok + ng) / 2;
            if (A[mid] < A[pos]) ok = mid;
            else ng = mid;

        }

        swap(A, pos, ok);
        reverse(A, pos + 1, len - 1);


        return true;
    }

    //↓nCrをmod計算するために必要。 ***factorial(N)を呼ぶ必要がある***
    static long ncr(int n, int r)
    {
        if (n < r) return 0;
        else if (r == 0) return 1;

        factorial(n);
        return F[n] / (F[n - r] * F[r]);
    }

    static long ncr2(int a, int b)
    {
        if (b == 0) return 1;
        else if (a < b) return 0;
        long res = 1;
        for (int i = 0; i < b; i++)
        {
            res *= a - i;
            res /= i + 1;
        }
        return res;
    }

    static long ncrdp(int n, int r)
    {
        if (n < r) return 0;
        long[][] dp = new long[n + 1][r + 1];
        for (int ni = 0; ni < n + 1; ni++)
        {
            dp[ni][0] = dp[ni][ni] = 1;
            for (int ri = 1; ri < ni; ri++)
            {
                dp[ni][ri] = dp[ni - 1][ri - 1] + dp[ni - 1][ri];
            }
        }
        return dp[n][r];
    }

    static long modNcr(int n, int r)
    {
        long result = F[n];
        result = result * modInv(F[n - r]) % MOD;
        result = result * modInv(F[r]) % MOD;
        return result;
    }

    static long modInv(long n)
    {
        return modPow(n, MOD - 2);
    }

    static void factorial(int n)
    {
        F = new long[n + 1];
        F[0] = F[1] = 1;
        for (int i = 2; i <= n; i++)
        {
            F[i] = (F[i - 1] * i) % MOD;
        }
    }

    static long modPow(long x, long n)
    {
        long res = 1L;
        while (n > 0)
        {
            if ((n & 1) == 1)
            {
                res = res * x % MOD;
            }
            x = x * x % MOD;
            n >>= 1;
        }
        return res;
    }

    //↑nCrをmod計算するために必要

    static int gcd(int n, int r)
    {
        return r == 0 ? n : gcd(r, n % r);
    }

    static long gcd(long n, long r)
    {
        return r == 0 ? n : gcd(r, n % r);
    }

    static <T> void swap(T[] x, int i, int j)
    {
        T t = x[i];
        x[i] = x[j];
        x[j] = t;
    }

    static void swap(int[] x, int i, int j)
    {
        int t = x[i];
        x[i] = x[j];
        x[j] = t;
    }

    public static void reverse(int[] x)
    {
        int l = 0;
        int r = x.length - 1;
        while (l < r)
        {
            int temp = x[l];
            x[l] = x[r];
            x[r] = temp;
            l++;
            r--;
        }
    }

    public static void reverse(long[] x)
    {
        int l = 0;
        int r = x.length - 1;
        while (l < r)
        {
            long temp = x[l];
            x[l] = x[r];
            x[r] = temp;
            l++;
            r--;
        }
    }

    public static void reverse(int[] x, int s, int e)
    {
        int l = s;
        int r = e;
        while (l < r)
        {
            int temp = x[l];
            x[l] = x[r];
            x[r] = temp;
            l++;
            r--;
        }
    }

    static int length(int a)
    {
        int cou = 0;
        while (a != 0)
        {
            a /= 10;
            cou++;
        }
        return cou;
    }

    static int length(long a)
    {
        int cou = 0;
        while (a != 0)
        {
            a /= 10;
            cou++;
        }
        return cou;
    }

    static int countC2(char[][] a, char c)
    {
        int co = 0;
        for (int i = 0; i < a.length; i++)
            for (int j = 0; j < a[0].length; j++)
                if (a[i][j] == c) co++;
        return co;
    }

    static int countI(int[] a, int key)
    {
        int co = 0;
        for (int i = 0; i < a.length; i++)
            if (a[i] == key) co++;
        return co;
    }

    static int countI(int[][] a, int key)
    {
        int co = 0;
        for (int i = 0; i < a.length; i++)
            for (int j = 0; j < a[0].length; j++)
                if (a[i][j] == key) co++;
        return co;
    }

    static void fill(int[][] a, int v)
    {
        for (int i = 0; i < a.length; i++)
            for (int j = 0; j < a[0].length; j++)
                a[i][j] = v;
    }


    static void fill(long[][] a, long v)
    {
        for (int i = 0; i < a.length; i++)
            for (int j = 0; j < a[0].length; j++)
                a[i][j] = v;
    }

    static void fill(int[][][] a, int v)
    {
        for (int i = 0; i < a.length; i++)
            for (int j = 0; j < a[0].length; j++)
                for (int k = 0; k < a[0][0].length; k++)
                    a[i][j][k] = v;
    }

    static int max(int a, int b, int c)
    {
        return Math.max(a, Math.max(b, c));
    }

    static int max(int[] ar)
    {
        int res = Integer.MIN_VALUE;
        for (int i : ar)
            res = Math.max(res, i);
        return res;
    }

    static int max(int[][] ar)
    {
        int res = Integer.MIN_VALUE;
        for (int i[] : ar)
            res = Math.max(res, max(i));
        return res;
    }

    static int min(int a, int b, int c)
    {
        return Math.min(a, Math.min(b, c));
    }

    static int min(int[] ar)
    {
        int res = Integer.MAX_VALUE;
        for (int i : ar)
            res = Math.min(res, i);
        return res;
    }

    static int min(int[][] ar)
    {
        int res = Integer.MAX_VALUE;
        for (int i[] : ar)
            res = Math.min(res, min(i));
        return res;
    }

    static int sum(int[] a)
    {
        int cou = 0;
        for (int i : a)
            cou += i;
        return cou;
    }

    static int abs(int a)
    {
        return Math.abs(a);
    }

    static class FastScanner
    {

        private BufferedReader reader = null;
        private StringTokenizer tokenizer = null;

        public FastScanner(InputStream in)
        {
            reader = new BufferedReader(new InputStreamReader(in));
            tokenizer = null;
        }

        public String next()
        {
            if (tokenizer == null || !tokenizer.hasMoreTokens())
            {
                try
                {
                    tokenizer = new StringTokenizer(reader.readLine());
                } catch (IOException e)
                {
                    throw new RuntimeException(e);
                }
            }
            return tokenizer.nextToken();
        }

        /*public String nextChar(){
            return (char)next()[0];
        }*/
        public String nextLine()
        {
            if (tokenizer == null || !tokenizer.hasMoreTokens())
            {
                try
                {
                    return reader.readLine();
                } catch (IOException e)
                {
                    throw new RuntimeException(e);
                }
            }

            return tokenizer.nextToken("\n");
        }

        public long nextLong()
        {
            return Long.parseLong(next());
        }

        public int nextInt()
        {
            return Integer.parseInt(next());
        }

        public double nextDouble()
        {
            return Double.parseDouble(next());
        }

        public int[] nextIntArray(int n)
        {
            int[] a = new int[n];
            for (int i = 0; i < n; i++)
            {
                a[i] = nextInt();
            }
            return a;
        }

        public int[] nextIntArrayDec(int n)
        {
            int[] a = new int[n];
            for (int i = 0; i < n; i++)
            {
                a[i] = nextInt() - 1;
            }
            return a;
        }

        public int[][] nextIntArray2(int h, int w)
        {
            int[][] a = new int[h][w];
            for (int hi = 0; hi < h; hi++)
            {
                for (int wi = 0; wi < w; wi++)
                {
                    a[hi][wi] = nextInt();
                }
            }
            return a;
        }

        public int[][] nextIntArray2Dec(int h, int w)
        {
            int[][] a = new int[h][w];
            for (int hi = 0; hi < h; hi++)
            {
                for (int wi = 0; wi < w; wi++)
                {
                    a[hi][wi] = nextInt() - 1;
                }
            }
            return a;
        }

        //複数の配列を受け取る
        public void nextIntArrays2ar(int[] a, int[] b)
        {
            for (int i = 0; i < a.length; i++)
            {
                a[i] = sc.nextInt();
                b[i] = sc.nextInt();
            }
        }

        public void nextIntArrays2arDec(int[] a, int[] b)
        {
            for (int i = 0; i < a.length; i++)
            {
                a[i] = sc.nextInt() - 1;
                b[i] = sc.nextInt() - 1;
            }
        }

        //複数の配列を受け取る
        public void nextIntArrays3ar(int[] a, int[] b, int[] c)
        {
            for (int i = 0; i < a.length; i++)
            {
                a[i] = sc.nextInt();
                b[i] = sc.nextInt();
                c[i] = sc.nextInt();
            }
        }

        //複数の配列を受け取る
        public void nextIntArrays3arDec(int[] a, int[] b, int[] c)
        {
            for (int i = 0; i < a.length; i++)
            {
                a[i] = sc.nextInt() - 1;
                b[i] = sc.nextInt() - 1;
                c[i] = sc.nextInt() - 1;
            }
        }

        public Integer[] nextIntegerArray(int n)
        {
            Integer[] a = new Integer[n];
            for (int i = 0; i < n; i++)
            {
                a[i] = nextInt();
            }
            return a;
        }

        public char[] nextCharArray(int n)
        {
            char[] a = next().toCharArray();

            return a;
        }

        public char[][] nextCharArray2(int h, int w)
        {
            char[][] a = new char[h][w];
            for (int i = 0; i < h; i++)
            {
                a[i] = next().toCharArray();
            }
            return a;
        }

        //スペースが入っている場合
        public char[][] nextCharArray2s(int h, int w)
        {
            char[][] a = new char[h][w];
            for (int i = 0; i < h; i++)
            {
                a[i] = nextLine().replace(" ", "").toCharArray();
            }
            return a;
        }

        public char[][] nextWrapCharArray2(int h, int w, char c)
        {
            char[][] a = new char[h + 2][w + 2];
            //char c = '*';
            int i;
            for (i = 0; i < w + 2; i++)
                a[0][i] = c;
            for (i = 1; i < h + 1; i++)
            {
                a[i] = (c + next() + c).toCharArray();
            }
            for (i = 0; i < w + 2; i++)
                a[h + 1][i] = c;
            return a;
        }

        //スペースが入ってる時用
        public char[][] nextWrapCharArray2s(int h, int w, char c)
        {
            char[][] a = new char[h + 2][w + 2];
            //char c = '*';
            int i;
            for (i = 0; i < w + 2; i++)
                a[0][i] = c;
            for (i = 1; i < h + 1; i++)
            {
                a[i] = (c + nextLine().replace(" ", "") + c).toCharArray();
            }
            for (i = 0; i < w + 2; i++)
                a[h + 1][i] = c;
            return a;
        }

        public long[] nextLongArray(int n)
        {
            long[] a = new long[n];
            for (int i = 0; i < n; i++)
            {
                a[i] = nextLong();
            }
            return a;
        }

        public long[][] nextLongArray2(int h, int w)
        {
            long[][] a = new long[h][w];
            for (int hi = 0; hi < h; hi++)
            {
                for (int wi = 0; wi < h; wi++)
                {
                    a[h][w] = nextLong();
                }
            }
            return a;
        }
    }
}

Submission Info

Submission Time
Task D - Fennec VS. Snuke
User baito
Language Java8 (OpenJDK 1.8.0)
Score 400
Code Size 25044 Byte
Status AC
Exec Time 363 ms
Memory 54216 KB

Judge Result

Set Name Sample All
Score / Max Score 0 / 0 400 / 400
Status
AC × 2
AC × 21
Set Name Test Cases
Sample 00_example_01.txt, 00_example_02.txt
All 00_example_01.txt, 00_example_02.txt, 01.txt, 02.txt, 03.txt, 04.txt, 05.txt, 06.txt, 07.txt, 08.txt, 09.txt, 10.txt, 11.txt, 12.txt, 13.txt, 14.txt, 15.txt, 16.txt, 17.txt, 18.txt, 19.txt
Case Name Status Exec Time Memory
00_example_01.txt AC 75 ms 21076 KB
00_example_02.txt AC 74 ms 20948 KB
01.txt AC 72 ms 21460 KB
02.txt AC 73 ms 19284 KB
03.txt AC 74 ms 19284 KB
04.txt AC 73 ms 18004 KB
05.txt AC 326 ms 52348 KB
06.txt AC 335 ms 52672 KB
07.txt AC 343 ms 52180 KB
08.txt AC 312 ms 52560 KB
09.txt AC 72 ms 20180 KB
10.txt AC 342 ms 52332 KB
11.txt AC 351 ms 52684 KB
12.txt AC 355 ms 50028 KB
13.txt AC 363 ms 54216 KB
14.txt AC 358 ms 51812 KB
15.txt AC 354 ms 52156 KB
16.txt AC 324 ms 51916 KB
17.txt AC 320 ms 52480 KB
18.txt AC 345 ms 48836 KB
19.txt AC 343 ms 53224 KB