可达性统计

AcWing

题意:给定一张N个点M条边的有向无环图,分别统计从每个点出发能够到达的点的数量.\((N,M<=30000)\)

分析:设\(f(x)\)表示x能够到达的点的集合,先求出该图的拓扑序,因为对于任意一条有向边(x,y),先要求出\(f(y)\)才能求出\(f(x)\).我们用\(bitset\)开f数组,把f[i]看作一个N位的二进制数,某一位为1则代表可以到达,对i的所有儿子做“按位或”运算即可把i的儿子能够到达的点统计到i上.

//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<bitset>
using namespace std;
inline int read(){
    int x=0,o=1;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')o=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*o;
}
const int N=30005;
int cnt,a[N];
int tot,head[N],nxt[N],to[N],deg[N];
bitset<N> f[N];
vector<int> Q[N];
queue<int>q;
inline void add(int a,int b){
	nxt[++tot]=head[a];head[a]=tot;to[tot]=b;
	++deg[b];
}
inline void topsort(int n){
	for(int i=1;i<=n;++i)if(!deg[i])q.push(i);
	while(q.size()){
		int u=q.front();q.pop();
		a[++cnt]=u;
		for(int i=head[u];i;i=nxt[i]){
			int v=to[i];f[u][v]=1;
			--deg[v];if(!deg[v])q.push(v);
		}
	}
}
int main(){
	int n=read(),m=read();
	for(int i=1;i<=m;++i){
		int x=read(),y=read();
		add(x,y);Q[x].push_back(y);
	}
	topsort(n);
	for(int i=cnt;i>=1;--i){
		for(int j=0;j<Q[a[i]].size();++j){
			f[a[i]]|=f[Q[a[i]][j]];
		}
	}
	for(int i=1;i<=n;++i)printf("%d\n",f[i].count()+1);
    return 0;
}

posted on 2019-07-26 08:59  PPXppx  阅读(335)  评论(0编辑  收藏  举报