#include <bits/stdc++.h>
using namespace std;
const int di[] = {-1, 0, 1, 0, -1, 1, 1, -1};
const int dj[] = {0, 1, 0, -1, -1, 1, -1, 1};
const long long MOD = 1e9 + 7;
const long long INF = 1e9;
const long double EPS = 1e-7;
class Graph {
  int V;
  list<int>* adj;
  void fillOrder(int v, bool visited[], stack<int>& Stack);
  void DFSUtil(int v, bool visited[], vector<long long>& ret);

 public:
  Graph(int V);
  void addEdge(int v, int w);
  vector<vector<long long> > printSCCs();
  Graph getTranspose();
};
Graph::Graph(int V) {
  this->V = V;
  adj = new list<int>[V];
}
void Graph::DFSUtil(int v, bool visited[], vector<long long>& ret) {
  visited[v] = true;
  ret.push_back(v);
  list<int>::iterator i;
  for (i = adj[v].begin(); i != adj[v].end(); ++i)
    if (!visited[*i]) DFSUtil(*i, visited, ret);
}
Graph Graph::getTranspose() {
  Graph g(V);
  for (int v = 0; v < V; v++) {
    list<int>::iterator i;
    for (i = adj[v].begin(); i != adj[v].end(); ++i) {
      g.adj[*i].push_back(v);
    }
  }
  return g;
}
void Graph::addEdge(int v, int w) { adj[v].push_back(w); }
void Graph::fillOrder(int v, bool visited[], stack<int>& Stack) {
  visited[v] = true;
  list<int>::iterator i;
  for (i = adj[v].begin(); i != adj[v].end(); ++i)
    if (!visited[*i]) fillOrder(*i, visited, Stack);
  Stack.push(v);
}
vector<vector<long long> > Graph::printSCCs() {
  stack<int> Stack;
  bool* visited = new bool[V];
  for (int i = 0; i < V; i++) visited[i] = false;
  for (int i = 0; i < V; i++)
    if (visited[i] == false) fillOrder(i, visited, Stack);
  Graph gr = getTranspose();
  for (int i = 0; i < V; i++) visited[i] = false;
  vector<vector<long long> > ret;
  while (Stack.empty() == false) {
    int v = Stack.top();
    Stack.pop();
    if (visited[v] == false) {
      ret.push_back({});
      gr.DFSUtil(v, visited, ret.back());
    }
  }
  return ret;
}
int n, m;
vector<vector<long long> > unadj, adj, comp;
vector<bool> vis;
void dfs(int node) {
  comp.back().push_back(node);
  vis[node] = true;
  for (int i = 0; i < unadj[node].size(); i++) {
    if (!vis[unadj[node][i]]) dfs(unadj[node][i]);
  }
}
int calc(vector<long long> cc) {
  sort(cc.begin(), cc.end());
  map<int, int> idx;
  for (int i = 0; i < cc.size(); i++) idx[cc[i]] = i;
  Graph g(cc.size());
  for (auto& i : cc) {
    for (auto& j : adj[i]) {
      if (binary_search(cc.begin(), cc.end(), j)) g.addEdge(idx[i], idx[j]);
    }
  }
  vector<vector<long long> > scc = g.printSCCs();
  int ret = 0;
  for (auto& i : scc)
    if (i.size() > 1) return cc.size();
  return cc.size() - 1;
}
int main() {
  ios::sync_with_stdio(false), cin.tie(0);
  cin >> n >> m;
  unadj.assign(n, vector<long long>());
  adj = unadj;
  vis.assign(n, false);
  for (int i = 0; i < m; i++) {
    int u, v;
    cin >> u >> v;
    u--, v--;
    adj[u].push_back(v);
    unadj[u].push_back(v);
    unadj[v].push_back(u);
  }
  for (int i = 0; i < n; i++) {
    if (!vis[i]) {
      comp.push_back({});
      dfs(i);
    }
  }
  int r = 0;
  for (int i = 0; i < comp.size(); i++) {
    r += calc(comp[i]);
  }
  cout << r << endl;
  cin.ignore(), cin.get();
}
