#include using namespace std; const int N = 30010, M = 30010; int n, m; int din[N]; bitset f[N]; // 这相当于一个二维数组,表示点i(一维),可以到达其它哪些点,用类似于二进制的方式描述 vector path; // 拓扑序路径 // 链式前向星 int e[M], h[N], idx, w[M], ne[M]; void add(int a, int b, int c = 0) { e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++; } void topsort() { queue q; for (int i = 1; i <= n; i++) if (!din[i]) q.push(i); while (q.size()) { int u = q.front(); q.pop(); path.push_back(u); for (int i = h[u]; ~i; i = ne[i]) { int v = e[i]; din[v]--; if (din[v] == 0) q.push(v); } } } int main() { memset(h, -1, sizeof h); scanf("%d %d", &n, &m); int a, b; while (m--) { scanf("%d %d", &a, &b); add(a, b); // a->b 有向图 din[b]++; } // 求拓扑序 topsort(); // 倒着dp, f[x]维护从x结点出发能访问到的所有结点的集合 for (int k = n - 1; k >= 0; k--) { // 倒序遍历拓扑序列 int u = path[k]; // 终点u f[u][u] = 1; // 自己到自己是一种方案u->u base case for (int i = h[u]; ~i; i = ne[i]) // 枚举节点u的每条出边 f[u] |= f[e[i]]; // 通过二进制或运算,可以获取到u点可以到达哪些点e[i] } // 输出个数 for (int i = 1; i <= n; i++) printf("%d\n", f[i].count()); return 0; }