#include <bits/stdc++.h>
using namespace std;
using vint = vector<long long>;
using pint = pair<long long, long long>;
using vpint = vector<pint>;
template <typename A, typename B>
inline void chmin(A& a, B b) {
  if (a > b) a = b;
}
template <typename A, typename B>
inline void chmax(A& a, B b) {
  if (a < b) a = b;
}
template <class A, class B>
ostream& operator<<(ostream& ost, const pair<A, B>& p) {
  ost << "{" << p.first << "," << p.second << "}";
  return ost;
}
template <class T>
ostream& operator<<(ostream& ost, const vector<T>& v) {
  ost << "{";
  for (long long i = 0; i < v.size(); i++) {
    if (i) ost << ",";
    ost << v[i];
  }
  ost << "}";
  return ost;
}
inline long long topbit(unsigned long long x) {
  return x ? 63 - __builtin_clzll(x) : -1;
}
inline long long popcount(unsigned long long x) {
  return __builtin_popcountll(x);
}
inline long long parity(unsigned long long x) { return __builtin_parity(x); }
namespace SCC {
void visit(const vector<vector<long long>>& G, vector<long long>& vs,
           vector<long long>& used, long long v) {
  used[v] = true;
  for (auto u : G[v]) {
    if (!used[u]) visit(G, vs, used, u);
  }
  vs.push_back(v);
}
void visit2(const vector<vector<long long>>& T, vector<long long>& used,
            vector<long long>& comp, vector<long long>& vec, long long k,
            long long v) {
  comp[v] = k;
  used[v] = true;
  vec.push_back(v);
  for (auto u : T[v]) {
    if (!used[u]) visit2(T, used, comp, vec, k, u);
  }
}
void decompose(const vector<vector<long long>>& G, vector<vector<long long>>& H,
               vector<long long>& comp) {
  vector<vector<long long>> T(G.size());
  for (long long i = 0; i < G.size(); i++) {
    for (auto v : G[i]) {
      T[v].push_back(i);
    }
  }
  comp.resize(G.size());
  vector<long long> vs(G.size());
  vector<long long> used(G.size());
  for (long long i = 0; i < G.size(); i++) {
    if (!used[i]) visit(G, vs, used, i);
  }
  reverse(vs.begin(), vs.end());
  fill(used.begin(), used.end(), 0);
  long long K = 0;
  vector<vector<long long>> S;
  for (auto v : vs) {
    if (!used[v]) {
      S.push_back(vector<long long>());
      visit2(T, used, comp, S.back(), K++, v);
    }
  }
  H.resize(K);
  fill(used.begin(), used.end(), 0);
  for (long long i = 0; i < K; i++) {
    for (auto v : S[i]) {
      for (auto u : G[v]) {
        if (used[comp[u]] || comp[v] == comp[u]) continue;
        used[comp[u]] = true;
        H[comp[v]].push_back(comp[u]);
      }
    }
    for (auto v : H[i]) used[v] = false;
  }
}
}  // namespace SCC
struct UnionFindTree {
  vector<int32_t> par, sz;
  vector<long long> cy;
  UnionFindTree(int32_t n = 0) : par(n), sz(n), cy(n) {
    for (int32_t i = 0; i < n; i++) {
      par[i] = i;
      sz[i] = 1;
    }
  }
  int32_t find(int32_t x) { return x == par[x] ? x : par[x] = find(par[x]); }
  void unite(int32_t x, int32_t y) {
    x = find(x);
    y = find(y);
    if (x == y) return;
    if (sz[x] < sz[y]) swap(x, y);
    sz[x] += sz[y];
    cy[x] |= cy[y];
    par[y] = x;
  }
  bool same(int32_t x, int32_t y) { return find(x) == find(y); }
  int32_t size(int32_t x) { return sz[find(x)]; }
};
signed main() {
  long long N, M;
  cin >> N >> M;
  vector<vint> G(N);
  for (long long i = 0; i < (M); i++) {
    long long a, b;
    cin >> a >> b;
    a--;
    b--;
    G[a].emplace_back(b);
  }
  vector<vint> H;
  vint comp;
  SCC::decompose(G, H, comp);
  vint cnt(H.size());
  for (long long i = 0; i < (N); i++) cnt[comp[i]]++;
  UnionFindTree uf(H.size());
  for (long long i = 0; i < (N); i++)
    for (auto j : G[i]) uf.unite(comp[i], comp[j]);
  for (long long i = 0; i < (H.size()); i++)
    if (cnt[i] > 1) uf.cy[uf.find(i)] = 1;
  long long ans = N;
  for (long long i = 0; i < (H.size()); i++)
    if (uf.find(i) == i && uf.cy[i] == 0) ans--;
  cout << ans << endl;
  return 0;
}
