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;
}
posted @ 2020-07-17 21:31  Luglucky  阅读(140)  评论(0编辑  收藏  举报