#include <iostream>
#include <algorithm>
#include <utility>
#include <vector>
#include <numeric>

template <class T, class U>
inline bool chmin(T &lhs, const U &rhs) {
  if (lhs > rhs) {
    lhs = rhs;
    return true;
  }
  return false;
}

template <class T, class U>
inline bool chmax(T &lhs, const U &rhs) {
  if (lhs < rhs) {
    lhs = rhs;
    return true;
  }
  return false;
}

// [l, r) from l to r
struct range {
  struct itr {
    int i;
    constexpr itr(int i_): i(i_) { }
    constexpr void operator ++ () { ++i; }
    constexpr int operator * () const { return i; }
    constexpr bool operator != (itr x) const { return i != x.i; }
  };
  const itr l, r;
  constexpr range(int l_, int r_): l(l_), r(std::max(l_, r_)) { }
  constexpr itr begin() const { return l; }
  constexpr itr end() const { return r; }
};

// [l, r) from r to l
struct revrange {
  struct itr {
    int i;
    constexpr itr(int i_): i(i_) { }
    constexpr void operator ++ () { --i; }
    constexpr int operator * () const { return i; }
    constexpr bool operator != (itr x) const { return i != x.i; }
  };
  const itr l, r;
  constexpr revrange(int l_, int r_): l(l_ - 1), r(std::max(l_, r_) - 1) { }
  constexpr itr begin() const { return r; }
  constexpr itr end() const { return l; }
};

template <class T>
struct fix_point: private T {
  explicit constexpr fix_point(T &&func): T(std::forward<T>(func)) { }
  template <class... Args>
  constexpr decltype(auto) operator () (Args &&... args) const {
    return T::operator()(*this, std::forward<Args>(args)...);
  }
};

template <class T>
constexpr decltype(auto) make_fix_point(T &&func) {
  return fix_point<T>{std::forward<T>(func)};
}

int main() {
  int N, M;
  std::cin >> N >> M;
  std::vector<std::vector<int>> graph(N);
  std::vector<std::vector<int>> revgraph(N);
  for (int i: range(0, M)) {
    int a, b;
    std::cin >> a >> b;
    --a; --b;
    graph[a].push_back(b);
    revgraph[b].push_back(a);
  }
  std::vector<bool> visited(N);
  std::vector<std::vector<int>> components;
  auto dfs = make_fix_point([&](auto dfs, int u) -> void {
    if (visited[u]) {
      return;
    }
    visited[u] = true;
    components.back().push_back(u);
    for (int v: graph[u]) {
      dfs(v);
    }
    for (int v: revgraph[u]) {
      dfs(v);
    }
  });
  for (int i: range(0, N)) {
    if (!visited[i]) {
      components.push_back({ });
      dfs(i);
    }
  }
  std::vector<int> color(N, -1);
  auto check = make_fix_point([&](auto check, int u, int c) -> bool {
    color[u] = c;
    int nc = (c + 1) % 3;
    for (int v: graph[u]) {
      if (color[v] != -1 && color[v] != nc) return false;
      if (color[v] == -1 && !check(v, nc)) return false;
    }
    int pc = (c + 2) % 3;
    for (int v: revgraph[u]) {
      if (color[v] != -1 && color[v] != pc) return false;
      if (color[v] == -1 && !check(v, pc)) return false;
    }
    return true;
  });
  long long ans = 0;
  for (const auto &group: components) {
    int u = group.front();
    if (check(u, 0)) {
      int cnt[3] = {};
      for (int x: group) {
        ++cnt[color[x]];
      }
      if (cnt[0] == 0 || cnt[1] == 0 || cnt[2] == 0) {
        for (int x: group) {
          ans += graph[x].size();
        }
      }
      else {
        ans += (long long) cnt[0] * cnt[1];
        ans += (long long) cnt[1] * cnt[2];
        ans += (long long) cnt[2] * cnt[0];
      }
    }
    else {
      int tmp = group.size();
      ans += (long long) tmp * tmp;
    }
  }
  std::cout << ans << '\n';
  return 0;
}


Measured memory_bytes: 44924