#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100010;
int par[MAXN], sub[MAXN];
void Init() {
  for (int i = 0; i < MAXN; ++i) par[i] = i;
}
int Get(int vr) { return par[vr] == vr ? vr : par[vr] = Get(par[vr]); }
void Merge(int a, int b) { par[Get(a)] = Get(b); }
void SetSub() {
  for (int i = 0; i < MAXN; ++i) ++sub[Get(i)];
}
int n, m;
vector<int> fo[MAXN], rev[MAXN];
vector<int> e[MAXN];
bool used[MAXN];
vector<int> ts;
void Dfs1(int vr) {
  used[vr] = true;
  for (int nxt : fo[vr])
    if (!used[nxt]) Dfs1(nxt);
  ts.push_back(vr);
}
void Dfs2(int vr) {
  used[vr] = true;
  for (int prev : rev[vr])
    if (!used[prev]) Merge(vr, prev), Dfs2(prev);
}
vector<int> comp;
void Dfs3(int vr) {
  used[vr] = true;
  comp.push_back(vr);
  for (int nxt : e[vr])
    if (!used[nxt]) Dfs3(nxt);
}
int main() {
  Init();
  scanf("%d%d", &n, &m);
  for (int i = 0; i < m; ++i) {
    int a, b;
    scanf("%d%d", &a, &b);
    --a, --b;
    fo[a].push_back(b), rev[b].push_back(a);
    e[a].push_back(b), e[b].push_back(a);
  }
  for (int i = 0; i < n; ++i)
    if (!used[i]) Dfs1(i);
  memset(used, 0, sizeof used);
  reverse(ts.begin(), ts.end());
  for (int i : ts)
    if (!used[i]) Dfs2(i);
  SetSub();
  memset(used, 0, sizeof used);
  int ans = 0;
  for (int i = 0; i < n; ++i)
    if (!used[i]) {
      bool has_cycle = false;
      comp.clear();
      Dfs3(i);
      for (int vr : comp)
        if (sub[Get(vr)] > 1) has_cycle = true;
      if (has_cycle)
        ans += ((int)(comp).size());
      else
        ans += ((int)(comp).size()) - 1;
    }
  cout << ans << '\n';
  return 0;
}
