#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = 10000+100;
int outdegree[maxn];
struct Tarjan
{
int V;
struct edge
{
int u, v;
int opp(int k) { return k==u?v:u; }
};
vector<edge> e; //边
vector<int> G[maxn]; //u连接的边
int DFN[maxn], low[maxn], sk[maxn];
int belong[maxn];
bool instack[maxn];
int top, Bcnt, Dindex;
void init()
{
e.clear();
for(int i=0; i<=V; i++) G[i].clear();
}
void add_edge(int u, int v)
{
e.push_back((edge){u, v});
G[u].push_back(e.size()-1);
}
void dfs(int u)
{
DFN[u]=low[u]=++Dindex;
instack[u] = true;
sk[++top] = u; //入栈
for(int i=0; i<G[u].size(); i++)
{
int v = G[u][i];
v = e[v].opp(u); //u连接的边v
if(!DFN[v])
{
dfs(v);
low[u] = min(low[u], low[v]);
}
else if(instack[v])
low[u] = min(low[u], DFN[v]);
}
if(DFN[u] == low[u])
{
Bcnt++;
int v;
do
{
v = sk[top--];
instack[v] = false;
belong[v]=Bcnt;
}while(v!=u);
}
}
void targan()
{
top = Bcnt = Dindex = 0;
memset(DFN, 0, sizeof(DFN));
for(int i=1; i<=V; i++)
if(!DFN[i]) dfs(i);
}
}ta;
int main()
{
int n, m; //n个顶点 m条边
scanf("%d%d", &n, &m);
ta.V = n;
ta.init();
for(int i=0; i<m; i++)
{
int u, v;
scanf("%d%d", &u, &v);
ta.add_edge(u, v);
}
ta.targan();
//他是先求后面的分量再求前面的分量
return 0;
}