#include <bits/stdc++.h>
using namespace std;
template <class T>
string tostring(T x) {
  ostringstream out;
  out << x;
  return out.str();
}
long long toint(string s) {
  istringstream in(s);
  long long x;
  in >> x;
  return x;
}
int dx[8] = {0, 0, 1, -1, 1, 1, -1, -1};
int dy[8] = {1, -1, 0, 0, -1, 1, -1, 1};
int kx[8] = {1, 1, -1, -1, 2, 2, -2, -2};
int ky[8] = {2, -2, 2, -2, 1, -1, 1, -1};
const int MAX = 111111;
vector<int> edges[MAX], edges2[MAX];
int res = 0;
bool vis[MAX];
int ind[MAX], low[MAX];
vector<int> s;
bool in[MAX];
int idx;
int color[MAX];
int sz[MAX];
int cc = 0;
void tarjan_dfs(int v) {
  ind[v] = idx;
  low[v] = idx++;
  s.push_back(v);
  in[v] = true;
  for (auto w : edges[v]) {
    if (ind[w] == -1) {
      tarjan_dfs(w);
      low[v] = min(low[v], low[w]);
    } else if (in[w]) {
      low[v] = min(low[v], ind[w]);
    }
  }
  if (low[v] == ind[v]) {
    int w;
    do {
      w = s.back();
      s.pop_back();
      in[w] = false;
      color[w] = cc;
      sz[cc]++;
    } while (v != w);
    cc++;
  }
}
vector<int> comp;
void dfs(int cur) {
  comp.push_back(cur);
  vis[cur] = true;
  for (auto child : edges2[cur]) {
    if (!vis[child]) {
      res++;
      dfs(child);
    }
  }
}
void solveOne() {
  int n, m;
  cin >> n >> m;
  for (int i = 0; i < n; i++) {
    edges[i].clear();
    edges2[i].clear();
  }
  for (int i = 0; i < m; i++) {
    int x, y;
    cin >> x >> y;
    x--, y--;
    edges[x].push_back(y);
    edges2[x].push_back(y);
    edges2[y].push_back(x);
  }
  memset(ind, -1, sizeof(ind));
  memset(sz, 0, sizeof(sz));
  idx = 0;
  cc = 0;
  for (int i = 0; i < n; i++)
    if (ind[i] == -1) tarjan_dfs(i);
  res = 0;
  memset(vis, false, sizeof(vis));
  for (int i = 0; i < n; i++)
    if (!vis[i]) {
      comp.clear();
      dfs(i);
      set<int> s;
      for (auto j : comp) s.insert(color[j]);
      if (s.size() < comp.size()) res++;
    }
  cout << res << endl;
}
int main() {
  std::ios::sync_with_stdio(false);
  int T = 1;
  while (T--) {
    solveOne();
  }
  return 0;
}
