#include <bits/stdc++.h>
using namespace std;
template <class T>
ostream &operator<<(ostream &os, const vector<T> &v) {
  os << "[";
  for (int i = 0; i < (((int)(v).size())); ++i) {
    if (i) os << ", ";
    os << v[i];
  }
  return os << "]";
}
template <class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
  return os << "(" << p.first << " " << p.second << ")";
}
template <class T>
bool chmax(T &a, const T &b) {
  if (a < b) {
    a = b;
    return true;
  }
  return false;
}
template <class T>
bool chmin(T &a, const T &b) {
  if (b < a) {
    a = b;
    return true;
  }
  return false;
}
using ll = long long;
using ull = unsigned long long;
using ld = long double;
using P = pair<int, int>;
using vi = vector<int>;
using vll = vector<ll>;
using vvi = vector<vi>;
using vvll = vector<vll>;
const ll MOD = 1e9 + 7;
const int INF = INT_MAX / 2;
const ll LINF = LLONG_MAX / 2;
const ld eps = 1e-9;
struct StronglyConnectedComponents {
  int n;
  vector<vector<int>> g, rg, graph;
  vector<int> ord, used, comp;
  StronglyConnectedComponents(const vector<vector<int>> &g)
      : n(g.size()), g(g), rg(n), used(n), comp(n, -1) {
    for (int i = 0; i < n; ++i) {
      for (int to : g[i]) {
        rg[to].push_back(i);
      }
    }
  }
  void build() {
    for (int i = 0; i < n; ++i) dfs(i);
    reverse(ord.begin(), ord.end());
    int ptr = 0;
    for (int i : ord)
      if (comp[i] == -1) rdfs(i, ptr), ptr++;
    graph.resize(ptr);
    for (int i = 0; i < n; ++i) {
      for (int to : g[i]) {
        int x = comp[i], y = comp[to];
        if (x == y) continue;
        graph[x].push_back(y);
      }
    }
    for (auto &v : graph) {
      sort(v.begin(), v.end());
      v.erase(unique(v.begin(), v.end()), v.end());
    }
  }

 private:
  void dfs(int idx) {
    if (used[idx]) return;
    used[idx] = true;
    for (int to : g[idx]) dfs(to);
    ord.push_back(idx);
  }
  void rdfs(int idx, int cnt) {
    if (comp[idx] != -1) return;
    comp[idx] = cnt;
    for (int to : rg[idx]) rdfs(to, cnt);
  }
};
struct UnionFind {
  vector<int> par, sz;
  UnionFind(int n) : par(n), sz(n, 1) {
    for (int i = 0; i < n; ++i) par[i] = i;
  }
  int root(int x) {
    if (par[x] == x) return x;
    return par[x] = root(par[x]);
  }
  void merge(int x, int y) {
    x = root(x);
    y = root(y);
    if (x == y) return;
    if (sz[x] < sz[y]) swap(x, y);
    par[y] = x;
    sz[x] += sz[y];
    sz[y] = 0;
  }
  bool issame(int x, int y) { return root(x) == root(y); }
  int size(int x) { return sz[root(x)]; }
};
int main() {
  cin.tie(0);
  ios::sync_with_stdio(false);
  cout << fixed << setprecision(10);
  int n, m;
  cin >> n >> m;
  vvi g(n);
  for (int i = 0; i < (m); ++i) {
    int u, v;
    cin >> u >> v;
    u--;
    v--;
    g[u].push_back(v);
  }
  StronglyConnectedComponents scc(g);
  scc.build();
  map<int, int> mp;
  for (int i = 0; i < (n); ++i) {
    mp[scc.comp[i]]++;
  }
  int sz = ((int)(scc.graph).size());
  UnionFind uf(sz);
  for (int i = 0; i < (sz); ++i) {
    for (auto &to : scc.graph[i]) {
      uf.merge(i, to);
    }
  }
  int ans = 0;
  map<int, int> cnt;
  map<int, bool> isn;
  for (int i = 0; i < (sz); ++i) {
    cnt[uf.root(i)] += mp[i];
    isn[uf.root(i)] |= mp[i] >= 2;
  }
  for (auto &e : cnt) {
    if (isn[e.first]) {
      ans += e.second;
    } else {
      ans += e.second - 1;
    }
  }
  cout << min(n, ans) << endl;
  return 0;
}
