#include <bits/stdc++.h>
using namespace std;
template <class T>
using vv = vector<vector<T>>;
template <class T>
ostream &operator<<(ostream &os, const vector<T> &t) {
  os << "{";
  for (int(i) = 0; (i) < (t.size()); ++(i)) {
    os << t[i] << ",";
  }
  os << "}" << endl;
  return os;
}
template <class S, class T>
ostream &operator<<(ostream &os, const pair<S, T> &t) {
  return os << "(" << t.first << "," << t.second << ")";
}
struct Edge {
  int src, dst;
  int weight;
  Edge(int src, int dst, int weight) : src(src), dst(dst), weight(weight) {}
};
ostream &operator<<(ostream &os, const Edge &e) {
  return cout << "(" << e.src << "," << e.dst << ")";
}
bool operator<(const Edge &e, const Edge &f) {
  return e.weight != f.weight ? e.weight > f.weight
         : e.src != f.src     ? e.src < f.src
                              : e.dst < f.dst;
}
bool operator==(const Edge &e, const Edge &f) {
  return e.src == f.src && e.dst == f.dst;
}
void visit(const vector<vector<Edge>> &g, int v, vector<vector<int>> &scc,
           stack<int> &S, vector<bool> &inS, vector<int> &low, vector<int> &num,
           int &time) {
  low[v] = num[v] = ++time;
  S.push(v);
  inS[v] = true;
  for (auto e : g[v]) {
    int w = e.dst;
    if (num[w] == 0) {
      visit(g, w, scc, S, inS, low, num, time);
      low[v] = min(low[v], low[w]);
    } else if (inS[w])
      low[v] = min(low[v], num[w]);
  }
  if (low[v] == num[v]) {
    scc.push_back(vector<int>());
    while (1) {
      int w = S.top();
      S.pop();
      inS[w] = false;
      scc.back().push_back(w);
      if (v == w) break;
    }
  }
}
void toDag(const vector<vector<Edge>> &g, const vector<vector<int>> &scc,
           vector<int> &dagV, vector<vector<Edge>> &dag) {
  dagV.resize(g.size());
  dag.resize(scc.size());
  for (int(i) = 0; (i) < (scc.size()); ++(i)) {
    for (int(j) = 0; (j) < (scc[i].size()); ++(j)) {
      dagV[scc[i][j]] = i;
    }
  }
  for (int(i) = 0; (i) < (scc.size()); ++(i)) {
    for (int(j) = 0; (j) < (scc[i].size()); ++(j)) {
      for (auto e : g[scc[i][j]]) {
        if (dagV[e.dst] != i) dag[i].push_back(Edge(i, dagV[e.dst], e.weight));
      }
    }
  }
}
vector<int> Scc(const vector<vector<Edge>> &g, vector<vector<int>> &scc,
                vector<vector<Edge>> &dag) {
  const int n = g.size();
  vector<int> num(n), low(n), dagV(n);
  stack<int> S;
  vector<bool> inS(n);
  int time = 0;
  for (int(u) = 0; (u) < (n); ++(u))
    if (num[u] == 0) visit(g, u, scc, S, inS, low, num, time);
  reverse((scc).begin(), (scc).end());
  toDag(g, scc, dagV, dag);
  for (int(i) = 0; (i) < (dag.size()); ++(i)) {
    dag[i].erase(unique((dag[i]).begin(), (dag[i]).end()), dag[i].end());
  }
  return dagV;
}
pair<int, int> count(vector<vector<Edge>> &g, vv<int> &scc, vector<int> &usd,
                     int v) {
  if (usd[v]) return pair<int, int>(0, 0);
  pair<int, int> re = pair<int, int>(scc[v].size(), scc[v].size() > 1), tmp;
  usd[v] = 1;
  for (Edge e : g[v])
    if (!usd[e.dst]) {
      tmp = count(g, scc, usd, e.dst);
      re.first += tmp.first;
      re.second |= tmp.second;
    }
  return re;
}
void ccdfs(vector<vector<Edge>> &g, vector<int> &cc, vector<int> &usd, int v) {
  if (usd[v]) return;
  usd[v] = 1;
  cc.push_back(v);
  for (const Edge &e : g[v])
    if (!usd[e.dst]) ccdfs(g, cc, usd, e.dst);
}
void CC(vector<vector<Edge>> &h, vv<int> &cc) {
  int n = h.size();
  vector<int> usd(n);
  vector<vector<Edge>> g = h;
  for (int(i) = 0; (i) < (n); ++(i))
    for (const Edge &e : h[i]) g[e.dst].push_back(Edge(e.dst, e.src, e.weight));
  for (int(i) = 0; (i) < (n); ++(i))
    if (!usd[i]) {
      cc.push_back(vector<int>());
      ccdfs(g, cc.back(), usd, i);
    }
}
bool topodfs(const vector<vector<Edge>> &g, int v, vector<int> &order,
             vector<int> &usd, vector<int> &ex) {
  usd[v] = 1;
  for (const Edge &e : g[v])
    if (*lower_bound((ex).begin(), (ex).end(), e.dst) == e.dst) {
      if (usd[e.dst] == 2) continue;
      if (usd[e.dst] == 1) return 0;
      if (!topodfs(g, e.dst, order, usd, ex)) return 0;
    }
  order.push_back(v);
  usd[v] = 2;
  return 1;
}
bool topoSort(const vector<vector<Edge>> &g, vector<int> &ex,
              vector<int> &order) {
  int n = g.size();
  vector<int> usd(n);
  for (int(i) = 0; (i) < (n); ++(i))
    if (!usd[i] && *lower_bound((ex).begin(), (ex).end(), i) == i)
      if (!topodfs(g, i, order, usd, ex)) return 0;
  reverse((order).begin(), (order).end());
  return 1;
}
int main() {
  ios_base::sync_with_stdio(false);
  cout << fixed << setprecision(0);
  int i, j, k;
  int n, m;
  scanf("%d %d", &n, &m);
  vector<vector<Edge>> g(n);
  int a, b;
  for (int(i) = 0; (i) < (m); ++(i)) {
    scanf("%d %d", &a, &b);
    --a;
    --b;
    g[a].push_back(Edge(a, b, 1));
  }
  vv<int> scc;
  vector<vector<Edge>> dag;
  Scc(g, scc, dag);
  int dn = scc.size(), re = 0;
  vector<int> usd(dn);
  vv<int> cc;
  CC(dag, cc);
  for (int(i) = 0; (i) < (cc.size()); ++(i)) {
    int f = 0;
    for (int(j) = 0; (j) < (cc[i].size()); ++(j)) {
      f |= (scc[cc[i][j]].size() > 1);
      re += scc[cc[i][j]].size();
    }
    if (!f) --re;
  }
  printf("%d\n", re);
  return 0;
}
