// 引入万能头文件,包含所有常用STL库
#include<bits/stdc++.h>
// 使用std命名空间,避免重复写std::
using namespace std;
// 定义常量N,表示节点数量的最大值(1e5+10)
const int N=1e5+10;
// 全局变量声明
int n,m; // n:总节点数,m:总边数
map<int,bool> f_eat; // 标记节点是否为可食用节点(出度为0的节点)
vector<int> plants; // 存储所有植物节点(入度为0的节点)
vector<int> G[N]; // 邻接表,存储有向图的边,G[u]表示u的所有后继节点
int r[N],c[N]; // r[u]:节点u的入度;c[u]:节点u的出度
int dp[N]; // 记忆化数组,dp[u]表示从u出发能到达的可食用节点总数
int res; // 最终结果,所有植物节点能到达的可食用节点总数
// 深度优先搜索函数:计算从节点u出发能到达的可食用节点总数
// 参数u:当前遍历的节点编号
// 返回值:从u出发能到达的可食用节点总数
int dfs(int u){
// 记忆化优化:如果dp[u]不为0,说明已经计算过,直接返回缓存结果
if(dp[u]!=0){
return dp[u];
}
// 如果当前节点是可食用节点(出度为0),返回1(自身是一个可食用节点)
if(f_eat[u]){
return 1;
}
// 遍历当前节点u的所有后继节点v
for(int v:G[u]){
// 累加每个后继节点v能到达的可食用节点数,存入dp[u]
dp[u]+=dfs(v);
}
// 返回当前节点u能到达的可食用节点总数
return dp[u];
}
// 核心求解函数:统计所有植物节点能到达的可食用节点总数并输出
void solve(){
// 遍历所有植物节点
for(int i=0;i<plants.size();i++){
// 累加每个植物节点能到达的可食用节点数到结果res中
res+=dfs(plants[i]);
}
// 输出最终结果
cout<<res<<endl;
}
// 主函数:程序入口
int main(){
// 关闭同步流,加速cin输入(竞赛常用优化)
ios::sync_with_stdio(false);
// 解绑cin和cout,进一步加速输入输出
cin.tie(0);
// 输入总节点数n和总边数m
cin>>n>>m;
int u,v;
// 循环输入m条有向边
for(int i=1;i<=m;i++){
cin>>u>>v;
// 构建邻接表:添加边u->v
G[u].push_back(v);
// v的入度加1
r[v]++;
// u的出度加1
c[u]++;
}
// 遍历所有节点,筛选植物节点和可食用节点
for(int i=1;i<=n;i++){
// 跳过孤立节点(入度和出度都为0),无实际意义
if(r[i]==0&&c[i]==0){
continue;
}
// 入度为0的节点是植物节点,加入plants数组
if(r[i]==0){
plants.push_back(i);
}
// 出度为0的节点是可食用节点,标记f_eat[i]=true
if(c[i]==0){
f_eat[i]=true;
}
}
// 调用求解函数
solve();
return 0;
}