Acwing 164 可达性统计 (拓扑排序+bitset)
题面
给定一张N个点M条边的有向无环图,分别统计从每个点出发能够到达的点的数量。
输入格式
第一行两个整数N,M,接下来M行每行两个整数x,y,表示从x到y的一条有向边。
输出格式
输出共N行,表示每个点能够到达的点的数量。
数据范围
1≤N,M≤30000
输入样例:
10 10
3 8
2 3
2 5
5 9
5 9
2 3
3 9
4 8
2 10
4 9
输出样例:
1
6
3
3
2
1
1
1
1
1
思路
30000的数据量,开邻接矩阵必然炸裂。所以这里我们搞一个骚一点操作,我们求出这个图的拓扑排序,然后用一个bitset来枚举每一个点是否可达。这里的稍微有个难点在于如何处理toposort,我们从后往前枚举,从集合的方向上考虑,自己必然可以到达自己,然后枚举这个点的每一个可达点,用一个异或操作去使得这些点的的可达集合中也存放这个点就好了。最后我们枚举一下每一个点的bitset数组中的1个数就好了。
代码实现
#include<iostream>
#include<cmath>
#include<queue>
#include<cstdio>
#include<bitset>
using namespace std;
const int maxn=30010;
int verse[maxn],nexta[maxn],head[maxn],tot,cnt;
int a[maxn],n,m,deg[maxn];
bitset <maxn> f[maxn];
void add (int x,int y) {
verse[++tot]=y;
nexta[tot]=head[x];
head[x]=tot;
deg[y]++;
}
inline void toposort () {
queue<int > q;
for (int i=1;i<=n;i++)
if (deg[i]==0)
q.push (i);
while (q.size ()) {
int x=q.front ();
a[++cnt]=x;
q.pop ();
for (int i=head[x];i;i=nexta[i]) {
int y=verse [i];
deg[y]--;
if (!deg[y]) q.push (y);
}
}
}
inline void solve () {
for (int i=cnt;i;i--) {
int x=a[i];
f[x][x]=1;
for (int j=head[x];j;j=nexta[j]) {
int y=verse[j];
f[x]|=f[y];
}
}
}
int main () {
cin>>n>>m;
for (int i=1,x,y;i<=m;i++) {
cin>>x>>y;
add (x,y);
}
toposort ();
solve ();
for (int i=1;i<=n;i++) {
cout<<f[i].count()<<endl;
}
return 0;
}