CH2101 可达性统计

题意

给定一张N个点M条边的有向无环图,分别统计从每个点出发能够到达的点的数量。N,M≤30000。

分析

有向无环图,可以按拓扑序逆序统计答案。可以用bitset维护可达性。

时间复杂度\(O(N (N+M)/32 )\),空间大小\(N^2/8\)字节。

代码

#include<bits/stdc++.h>
#define rg register
#define il inline
#define co const
template<class T>il T read(){
    rg T data=0,w=1;
    rg char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-') w=-1;
        ch=getchar();
    }
    while(isdigit(ch))
        data=data*10+ch-'0',ch=getchar();
    return data*w;
}
template<class T>il T read(rg T&x){
    return x=read<T>();
}
typedef long long LL;
using namespace std;

co int N=3e4+1;
int n,m,deg[N],a[N];
int ver[N],Next[N],head[N],tot,cnt;
bitset<N> f[N];
void add(int x,int y){
    ver[++tot]=y,Next[tot]=head[x],head[x]=tot;
    ++deg[y];
}
void topsort(){
    queue<int> q;
    for(int i=1;i<=n;++i)
        if(deg[i]==0) q.push(i);
    while(q.size()){
        int x=q.front();q.pop();
        a[++cnt]=x;
        for(int i=head[x];i;i=Next[i]){
            int y=ver[i];
            if(--deg[y]==0) q.push(y);
        }
    }
}
void calc(){
    for(int i=cnt;i;--i){
        int x=a[i];
        f[x][x]=1;
        for(int i=head[x];i;i=Next[i]){
            int y=ver[i];
            f[x]|=f[y];
        }
    }
}
int main(){
//  freopen(".in","r",stdin);
//  freopen(".out","w",stdout);
    read(n),read(m);
    for(int i=1,x,y;i<=m;++i){
        read(x),read(y);
        add(x,y);
    }
    topsort();
    calc();
    for(int i=1;i<=n;++i) printf("%llu\n",f[i].count());
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/autoint/p/10419979.html