#include <bits/stdc++.h>
using namespace std;
#define endl "\n"
#define int long long
#define float double
int N, M;
bool Visit[100001];
vector<int> A[100001];
vector<int> B[100001];
stack<int> STACK;
vector<vector<int>> Group;
int P[100001];
int FindP(int a)
{
if (P[a] == a)
return a;
else
{
int emp = FindP(P[a]);
P[a] = emp;
return emp;
}
}
void Union(int a, int b)
{
P[FindP(b)] = P[FindP(a)];
}
void DFS_A(int n)
{
Visit[n] = true;
for (int i = 0; i < A[n].size(); i++)
{
int next = A[n][i];
if (Visit[next])
continue;
DFS_A(next);
}
STACK.push(n);
}
void DFS_B(int n, vector<int>& SCC)
{
Visit[n] = true;
SCC.push_back(n);
for (int i = 0; i < B[n].size(); i++)
{
int next = B[n][i];
if (Visit[next])
continue;
DFS_B(next, SCC);
}
}
bool ComeNode[100001];
int32_t main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
cin >> N >> M;
for (int i = 0; i < M; i++)
{
int a, b;
cin >> a >> b;
A[a].push_back(b);
B[b].push_back(a);
}
for (int i = 1; i <= N; i++)
P[i] = i;
for (int i = 1; i <= N; i++)
if (!Visit[i])
DFS_A(i);
memset(Visit, false, sizeof(Visit));
while (!STACK.empty())
{
vector<int> temp;
int next = STACK.top();
STACK.pop();
if (Visit[next])
continue;
DFS_B(next, temp);
Group.push_back(temp);
}
for (int i = 0; i < Group.size(); i++)
for (int j = 1; j < Group[i].size(); j++)
Union(Group[i][0], Group[i][j]);
int ans = 0;
for (int i = 1; i <= N; i++)
for (int j = 0; j < A[i].size(); j++)
{
int a = FindP(i);
int b = FindP(A[i][j]);
if (a != b)
ComeNode[b] = true;
}
memset(Visit, false, sizeof(Visit));
for (int i = 1; i <= N; i++)
{
int a = FindP(i);
if (!Visit[a] && !ComeNode[a])
{
DFS_A(a);
ans++;
}
}
cout << ans << endl;
}