Problem:
Score : 100 points

Problem Statement

There is a directed graph G with N vertices and M edges.
The vertices are numbered 1, 2, \ldots, N, and for each i (1 \leq i \leq M), the i-th directed edge goes from Vertex x_i to y_i.
G does not contain directed cycles.

Find the length of the longest directed path in G.
Here, the length of a directed path is the number of edges in it.

Constraints

All values in input are integers.

2 \leq N \leq 10^5

1 \leq M \leq 10^5

1 \leq x_i, y_i \leq N

All pairs (x_i, y_i) are distinct.

G does not contain directed cycles.

Input

Input is given from Standard Input in the following format:

N M
x_1 y_1
x_2 y_2
:
x_M y_M

Output

Print the length of the longest directed path in G.

Sample Input 1

4 5
1 2
1 3
3 2
2 4
3 4

Sample Output 1

3

The red directed path in the following figure is the longest:

Sample Input 2

6 3
2 3
4 5
5 6

Sample Output 2

2

The red directed path in the following figure is the longest:

Sample Input 3

5 8
5 3
2 3
2 4
5 2
5 1
1 4
4 3
1 3

Sample Output 3

3

The red directed path in the following figure is one of the longest:

Solution in Java8 (OpenJDK 1.8.0) (judge verdict: Wrong Answer)

import java.util.HashSet;
        import java.util.Objects;
        import java.util.PriorityQueue;
        import java.util.Scanner;
        import java.util.Set;

public class Main {
    public static class Node implements Comparable<Node>{
        Set<Integer> father;
        Set<Integer> son;
        int index;

        public Node() {
            father = new HashSet<>();
            son = new HashSet<>();
        }

        public Node(Set<Integer> father, Set<Integer> son, int index) {
            this.father = father;
            this.son = son;
            this.index = index;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Node node = (Node) o;
            return index == node.index &&
                    Objects.equals(father, node.father) &&
                    Objects.equals(son, node.son);
        }

        @Override
        public int hashCode() {
            return Objects.hash(father, son, index);
        }

        @Override
        public int compareTo(Node o) {
            if (this.father.size() == o.father.size()) {
                return 0;
            } else if (this.father.size() < o.father.size()) {
                return -1;
            } else {
                return 1;
            }
        }
    }
    public static void main(String [] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int m = scanner.nextInt();
        Node[] graph = new Node[n + 1];
        Set<Integer> visited = new HashSet<>();
        PriorityQueue<Node> nodes = new PriorityQueue<>();
        for (int i = 1; i <= n; ++i) {
            graph[i] = new Node();
            graph[i].index = i;
        }

        for (int i = 1; i <= m; ++i) {
            int x = scanner.nextInt();
            int y = scanner.nextInt();
            graph[x].son.add(y);
            graph[y].father.add(x);
        }
        for (int i = 1; i <= n; ++i) {
            Node newNode = new Node(graph[i].father, graph[i].son, i);
            nodes.add(newNode);
        }

        long [] path = new long[n + 1];

        while (!nodes.isEmpty()) {
            Node currentHead = nodes.poll();
            //    System.out.println("currentHead: " + currentHead.index);
            if (visited.contains(currentHead.index)) {
                continue;
            }
            for (Integer son : currentHead.son) {
                //      System.out.println("current son: " + son);
                path[son] = Math.max(path[son], path[currentHead.index] + 1L);
                graph[son].father.remove(currentHead.index);
                //   graph[currentHead.index].son.remove(son);
                Node newSon = new Node(graph[son].father, graph[son].son, son);
                nodes.add(newSon);
            }
            currentHead.son.clear();
            visited.add(currentHead.index);
        }

        long result = 0;
        for (int i = 1; i <= n; ++i) {
            result = Math.max(result, path[i]);
        }

        System.out.println(result);
    }
}