#include "bits/stdc++.h"

using namespace std;

using i64 = long long;

const i64 MOD = 1e9 + 7;
const i64 INF = i64(1e18) + 7;


template <typename T>
bool chmin(T& x, T y){
    if(x > y){
        x = y;
        return true;
    }
    return false;
}

template <typename T>
bool chmax(T& x, T y){
    if(x < y){
        x = y;
        return true;
    }
    return false;
}

struct UnionFind{
    vector<int> par;
    int count;
    UnionFind(int n) : par(n, -1), count(0){}
    int Find(int x){return par[x] < 0 ? x : Find(par[x]);}
    int Size(int x){return par[x] < 0 ? -par[x] : Size(par[x]);}
    bool Unite(int x, int y){
        x = Find(x);
        y = Find(y);
        if(x == y)
            return false;
        if(par[x] > par[y])
            swap(x, y);
        par[x] += par[y];
        par[y] = x;
        return ++count;
    }
};

vector<int> scc(vector<vector<int>>& edges){
    int n = edges.size();
    vector<vector<int>> rev(n);

    for(int i = 0; i < n; ++i)
        for(auto& x : edges[i])
            rev[x].emplace_back(i);

    vector<i64> dfs_num(n, -1);
    vector<i64> flag(n, 0);
    int num = 0;
    function<void(int)> dfs = [&](int pos){
        flag[pos] = 1;
        for(auto& xx : edges[pos])
            if(!flag[xx]){
                dfs(xx);
        }
        dfs_num[pos] = num++;
    };

    for(int i = 0; i < n; ++i)
        if(!flag[i])
            dfs(i);

    vector<int> dfs_inv(n);
    for(int i = 0; i < n; ++i)
        dfs_inv[n - 1 - dfs_num[i]] = i;

    num = 0;

    vector<int> scc_vec(n, -1);

    function<void(int)> rdfs = [&](int pos){
        scc_vec[pos] = num;
        for(auto t : rev[pos])
            if(scc_vec[t] == -1)
                rdfs(t);
    };

    for(int i = 0; i < n; ++i)
        if(scc_vec[dfs_inv[i]] == -1){
            rdfs(dfs_inv[i]);
            ++num;
        }

    return scc_vec;
}

signed main(){
    int n, m;
    cin >> n >> m;
    vector<int> s(m), t(m);
    vector<int> cnt(n, 0);
    for(int i = 0; i < m; ++i){
        cin >> s[i] >> t[i];
        --cnt[s[i]];
        ++cnt[t[i]];
    }
    UnionFind u(n);
    for(int i = 0; i < m; ++i)
        u.Unite(s[i], t[i]);

    vector<int> pv;
    for(int i = 0; i < n; ++i)
        if(u.Find(i) == i)
            pv.push_back(i);

    int k = pv.size();

    // idx to
    vector<int> par(n);
    vector<vector<int>> v(k);
    for(int i = 0; i < n; ++i){
        int idx = distance(pv.begin(), lower_bound(pv.begin(), pv.end(), u.Find(i)));
        par[i] = idx;
        v[idx].push_back(i);
    }

    vector<vector<vector<int>>> edges(k);
    for(int i = 0; i < k; ++i)
        edges[i].resize(v[i].size());
    for(int i = 0; i < m; ++i){
        int idx = par[s[i]];
        int from_idx = distance(v[idx].begin(), lower_bound(v[idx].begin(), v[idx].end(), s[i]));
        int to_idx = distance(v[idx].begin(), lower_bound(v[idx].begin(), v[idx].end(), t[i]));
        edges[idx][from_idx].emplace_back(to_idx);
    }

    int v_in = 0, v_out = 0;
    for(int i = 0; i < k; ++i){
        int l = edges[i].size();
        vector<int> w = scc(edges[i]);
        int p = *max_element(w.begin(), w.end()) + 1;
        if(k == 1 && p == 1){
            cout << 0 << endl;
            return 0;
        }
        vector<int> in_cnt(p, 0), out_cnt(p, 0);
        for(int j = 0; j < l; ++j)
            for(auto& k : edges[i][j]){
                if(w[k] != w[j]){
                    ++in_cnt[w[k]];
                    ++out_cnt[w[j]];
                }
            }

        for(int j = 0; j < p; ++j){
            if(in_cnt[j] == 0)
                ++v_in;
            if(out_cnt[j] == 0)
                ++v_out;
        }
    }

    cout << max(v_in, v_out) << endl;

}



Measured memory_bytes: 6500