#include<iostream>
#include<algorithm>
#include<vector>
#include<string>
#include<set>
#include<queue>
#include<stack>
#include<bitset>
#include<functional>
#include<map>
#include<unordered_set>
using namespace std;
//int p = 998244353;
long long p = 1000000007;
#define int long long
#define vel vector<long long>
#define vvel vector<vel>
#define rep(i,n) for(int i=0;i<n;i++)
#define sor(v) sort(v.begin(),v.end())
#define mmax(a,b) a=max(a,b)
#define mmin(a,b) a=min(a,b)
#define mkp make_pair
#define pin pair<int,int>
#define qin pair<int,pin>
#define V vector
#define Endl endl
#define veb vector<bool>
#define rev(s) reverse(s.begin(),s.end())
#define lower(h,val) lower_bound(h.begin(),h.end(),val)-h.begin()
#define upper(h,val) upper_bound(h.begin(),h.end(),val)-h.begin()
int max_kai = 150000;
vel kai(max_kai, 1);
vel inv_kai;
int rui(int a, int n) {
	if (n == 0) { return 1; }
	int x = rui(a, n / 2);
	x *= x; x %= p;
	if (n % 2 == 1) { x *= a; x %= p; }
	return x;
}
int inv(int a) { return rui(a, p - 2); }
void make_kai() {
	for (int i = 1; i < max_kai; i++) { kai[i] = kai[i - 1] * i; kai[i] %= p; }
	inv_kai = kai;
	rep(i, max_kai) { inv_kai[i] = inv(kai[i]); }
}
int nCr(int n, int r) {
	int a = kai[n] * inv_kai[r]; a %= p;
	a *= inv_kai[n - r]; a %= p;
	return a;
}
vel pa;
int root(int x) {
	if (pa[x] == -1) { return x; }
	int ans = root(pa[x]); pa[x] = ans;
	return ans;
}
void marge(int x, int y) {
	x = root(x);
	y = root(y);
	if (x != y) { pa[x] = y; }
}


#define T vel
T mul(T & a, T & b) {//calcureate a(b(x))
	int sz = a.size();
	vel c(sz);
	rep(i, sz) { c[i] = a[b[i]]; }
	return c;
}
T rui1(T & a, int n) {
	if (n == 1) { return a; }
	T x = rui1(a, n / 2);
	x = mul(x, x);
	if (n % 2 == 1) { x = mul(x, a); }
	return x;
}
void solve(V<V<pin>>& way, vel& con,vel &dist,int now_pot,veb &seen,bool& fl) {
	if (!seen[now_pot]) {
		seen[now_pot]=true;
		con.push_back(now_pot);
		for (auto next : way[now_pot]) {
			int ne_dist = dist[now_pot] + next.second;
			ne_dist %= 3;
			int ne_pot = next.first;
			if (dist[ne_pot] == -1) {
				dist[ne_pot] = ne_dist;
				solve(way, con, dist, ne_pot, seen, fl);
			}
			else {
				if (dist[ne_pot] != ne_dist) {
					fl = true;
				}
			}
		}
	}
}
signed main(){
	int n, m; cin >> n >> m;
	V<V<pin>> way(n);
	rep(i, m) {
		int a, b; cin >> a >> b;
		a--; b--;
		way[a].push_back(mkp(b,1));
		way[b].push_back(mkp(a,2));
	}
	vel dist(n, -1);
	int ans = 0;
	veb seen(n, false);
	rep(i, n) {
		if (dist[i] == -1) {
			vel list;
			bool fl = false;
			dist[i] = 0;
			solve(way, list,dist,i,seen,fl);
			int sz = list.size();
			if (fl) {ans += (sz * sz);}
			else {
				bool fl2 = false;
				vvel d_list(3);
				int count_way = 0;
				for(auto x:list){
					if (way[x].size() != 0) {
						for (auto y : way[x]) {
							if (y.second != way[x][0].second) { fl2 = true; }
							count_way++;
						}
					}
					d_list[dist[x] % 3].push_back(x);
				}
				if (fl2) {
					ans += d_list[0].size() * d_list[1].size();
					ans += d_list[1].size() * d_list[2].size();
					ans += d_list[2].size() * d_list[0].size();
				}
				else {
					ans += count_way/2;
				}
			}
		}
	}
	cout << ans << endl;
	return 0;
}

Measured memory_bytes: 20980