Problem:
Score : 1700 points

Problem Statement

We have a grid with N rows and N columns.
The cell at the i-th row and j-th column is denoted (i, j).

Initially, M of the cells are painted black, and all other cells are white.
Specifically, the cells (a_1, b_1), (a_2, b_2), ..., (a_M, b_M) are painted black.

Snuke will try to paint as many white cells black as possible, according to the following rule:

If two cells (x, y) and (y, z) are both black and a cell (z, x) is white for integers 1≤x,y,z≤N, paint the cell (z, x) black.

Find the number of black cells when no more white cells can be painted black.

Constraints

1≤N≤10^5

1≤M≤10^5

1≤a_i,b_i≤N

All pairs (a_i, b_i) are distinct.

Input

The input is given from Standard Input in the following format:

N M
a_1 b_1
a_2 b_2
:
a_M b_M

Output

Print the number of black cells when no more white cells can be painted black.

Sample Input 1

3 2
1 2
2 3

Sample Output 1

3

It is possible to paint one white cell black, as follows:

Since cells (1, 2) and (2, 3) are both black and a cell (3, 1) is white, paint the cell (3, 1) black.

Sample Input 2

2 2
1 1
1 2

Sample Output 2

4

It is possible to paint two white cells black, as follows:

Since cells (1, 1) and (1, 2) are both black and a cell (2, 1) is white, paint the cell (2, 1) black.

Since cells (2, 1) and (1, 2) are both black and a cell (2, 2) is white, paint the cell (2, 2) black.

Sample Input 3

4 3
1 2
1 3
4 4

Sample Output 3

3

No white cells can be painted black.

Solution in Java8 (OpenJDK 1.8.0) (judge verdict: Memory Limit Exceeded)

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

/**
 *  http://agc006.contest.atcoder.jp/tasks/agc006_f
 * 
 * @author Cummin
 */
public class Main {
    static int N ; // N<10^5
    static int M ; // M<10^5
    static Node[] index ; 
    
    static class Node {
        int visit ;
        int upstream ;  // starting point 
        List<Integer> next ;
        Node() {
            next = new ArrayList<>() ;
            this.upstream = 1 ;
        }
    }
    static int black_cnt ;

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        N = sc.nextInt();
        M = sc.nextInt();
        index = new Node[N] ;
        black_cnt = 0 ;
        for (int i=0 ; i<M; i++) {
            int x, y ;
            x = sc.nextInt()-1 ;  // x
            y = sc.nextInt()-1 ;  // y
            create(x, y) ;
        }
//        dump_tree() ;
        solve() ;
        System.out.println(black_cnt);
//        System.out.printf("\nANS=%d \n",black_cnt);
//        dump_tree() ;
//        dump_mat() ;
    }
    
    static void create(int x, int y) {
        if (index[x]==null) {
            index[x] = new Node() ;
        }
        add(x, y) ;
    }
    static void add(int x, int y) {
//        System.out.printf("add x:%d, y:%d  ", x+1, y+1) ;
        Node n ;
        n = index[x] ;
        n.next.add(y) ;
        if (index[y]==null) {
            index[y]= new Node() ;
        }
        index[y].upstream = 0 ;
        black_cnt ++ ;
    }

    static void solve() {
        //  Treeの端点からスタート
        for (int i=0 ; i<N ; i++){
            if (index[i] ==null)continue ;
            if (index[i].upstream==1 ) {
                index[i].visit = 1 ;
                solve2(i) ;
            }
        }
//        System.out.printf("*********************\n") ;
        // Treeの形がループの場合
        for (int i=0 ; i< N ; i++) {
            if (index[i] == null) continue ;
            if (index[i].visit == 0) {
//                System.out.printf("\nSolve: %d", i+1) ;
                index[i].visit = 1 ;
                solve2(i) ;
            }
        }
    }
    static void solve2(int nd) {  // nd: 評価するノード
        for (int ii = 0; ii < index[nd].next.size() ; ii++) {
            int i = index[nd].next.get(ii) ;
            if (index[i]== null) continue ;
            for (int jj = 0 ; jj < index[i].next.size(); jj++){
                int j = index[i].next.get(jj) ;
//        System.out.printf("\nSolve2 x:%d -> y:%d -> z:%d ", nd+1, i+1,j+1) ;
                check_and_set(j,nd) ;
            }
            if (index[i].visit == 1) return ;
            solve2(i) ;
        }
        index[nd].visit = 1 ;
    }
    static void check_and_set(int x, int y) {
        if (index[x] == null) {
//            System.out.printf(" CREATE node[%d] ", x+1) ;
            create(x, y) ;
            return ;
        }
        if (index[x].next.contains(y)) return ;
        add(x,y) ;
    }

    static void dump_mat() {
        for (int iy=0 ;iy<N ;iy++) {
            for (int ix=0 ;ix<N; ix++) {
                if (index[ix]== null) {
                    System.out.printf(".") ;
                } else if (index[ix].next.contains(iy)) {
                    System.out.printf("*") ;
                } else System.out.printf(".") ;
            }
            System.out.println() ;
        }
    }
    static void dump_tree() {
        System.out.println();
        for (int i = 0; i < N; i++) {
            if (index[i] == null) {
                continue;
            }
            System.out.printf("[%d]:", i+1);
            for (int j : index[i].next) {
                System.out.printf("--> %d ", j+1);
            }
            System.out.println();
        }
        System.out.println();
    }
}
/*
    static void solve2(int n) {
        // for (Integer i: index[n].next) {　ではエラーになる
        // 拡張forを使うと　java.util.ConcurrentModificationExceptionのエラーが発生する
        // これは、https://teratail.com/questions/16901　にあるように、ArrayListに要素を追加すると
        // 内部で保持しているIteratorの「変更された回数」（サイズ）とミスマッチが発生する

        for (int ii = 0; ii < index[n].next.size() ; ii++) {
            int i = index[n].next.get(ii) ;

            if (index[i]== null) continue ;
            // for (Integer j: index[i].next) {  // 同上
            for (int jj = 0 ; jj < index[i].next.size(); jj++){
                int j = index[i].next.get(jj) ;
//        System.out.printf("\nSolve2 x:%d -> y:%d -> z:%d ", n+1, i+1,j+1) ;
                check_and_set(j,n) ;
            }
        }
    }
*/