题意:给定一张N个点,M条边的有向无环图,分别统计从每个点出发能到达的点的数量。N,M<=30000。
题解:用拓扑排序将N个点排序,然后按照从后往前的顺序进行计算。
我们使用一个N位二进制来表示可达性,这样一来,对于若干个集合的求并操作,就变为了“按位或”操作。
//没时间写,代码是抄的 #include<cstdio> #include<queue> #include<bitset> #include<cstring> using namespace std; const int N=3e4+10; bitset<N>f[N]; queue<int>q; int head[N],tot,n,m,deg[N],tps[N],tp; struct Edge{ int v,nx; }e[N]; inline void addedge(int u,int v) { e[tot].v=v; e[tot].nx=head[u]; head[u]=tot++; deg[v]++; } void toposort() { for(int i=1;i<=n;i++)if(!deg[i])q.push(i); while(!q.empty()) { int u=q.front();q.pop();tps[++tp]=u; for(int i=head[u];~i;i=e[i].nx) { int v=e[i].v; if(--deg[v]==0)q.push(v); } } } int main() { //freopen("in.txt","r",stdin); memset(head,-1,sizeof(head)); scanf("%d%d",&n,&m); int u,v; for(int i=1;i<=m;i++)scanf("%d%d",&u,&v),addedge(u,v); toposort(); for(int i=tp;i;i--) { u=tps[i]; f[u][u]=1; for(int j=head[u];~j;j=e[j].nx) { v=e[j].v; f[u]|=f[v]; } } for(int i=1;i<=n;i++)printf("%d\n",f[i].count()); return 0; }