设从点 x 出发能够到达的点构成的集合是 f(x),从点 x 出发能够到达的点,是从 x 的各个后继节点 y 出发能够到达的点的并集,再加上点 x 自身 。
比如从2出发可以到达点5 8 9,则f(2)=f(5)Uf(8)Uf(9)
先按照拓扑排序算法求出拓扑序,然后按照拓扑序的倒序进行计算------因为在拓扑序中,任意一条边 (x , y),x 都排在 y 之前。
我们可以用一个N位2进制数来表示每个f(x),二进制数的第i位为1表示x可以到达点i,二进制中1的个数就是这个点可以到达的点的数目,这样一来,对若干个集合求并集,就是对若干个N位二进制数做按位或
用bitset存储f(x)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 3e4 + 10;
vector<int>edge[maxn], ans;
queue<int> que;
bitset<maxn> b[maxn];
int in[maxn], n, m,x,y;
void topo_sort()
{
for (int i = 1; i <= n;i++)
if (!in[i]) que.push(i);
while (!que.empty())
{
int v = que.front();
que.pop();
ans.push_back(v);
for (int i = 0; i < edge[v].size(); i++)
{
if (--in[edge[v][i]] == 0)
que.push(edge[v][i]);
}
}
}
void solve()
{
topo_sort();
for (int i = ans.size() - 1; i>=0; i--)
{
int v = ans[i];
//b[v].reset();
b[v][v] = 1;
for (int j = 0; j < edge[v].size(); j++)
{
b[v] |= b[edge[v][j]];
}
}
for (int i = 1; i <= n; i++)
cout << b[i].count() << endl;
}
int main()
{
cin >> n >> m;
for (int i = 1; i <= m; i++)
{
cin >> x >> y;
edge[x].push_back(y);
in[y]++;
}
solve();
return 0;
}