b_aw_可达性统计(拓扑排序+bitset)
N个点M条边的有向无环图,分别统计从每个点出发能够到达的点的数量(1≤N,M≤30000)
topo排序:图G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在v之前。
有了topo序,则可以利用倒序遍历topo序来优化算法,因为path[i-1]在DAU中出现path[i]之前,所以先更新后面的结点的可达结点
import java.util.*;
import java.io.*;
class Solution {
int n,m,in[],path[],k;
List<Integer> g[];
BitSet f[];
boolean vis[];
void topo() {
Queue<Integer> q=new LinkedList<>();
for (int i=1; i<=n; i++) if (in[i]==0)
q.add(i);
while (!q.isEmpty()) {
int u=q.poll();
path[k++]=u;
for (int v : g[u]) if (--in[v]==0) {
q.add(v);
}
}
}
void init() throws IOException {
Scanner sc = new Scanner(new BufferedInputStream(System.in));
n=sc.nextInt(); m=sc.nextInt(); in=new int[n+1]; vis=new boolean[n+1];
g=new ArrayList[n+1]; f=new BitSet[n+1]; path=new int[n+1];
for (int i=1; i<=n; i++) {
g[i]=new ArrayList<>();
f[i]=new BitSet();
}
for (int i=0; i<m; i++) {
int u=sc.nextInt(), v=sc.nextInt();
g[u].add(v); in[v]++;
}
topo(); //topo序就是一条有向的相邻结点可达的路径
for (int i=k-1; i>=0; i--) { //从后往前遍历topo序上的点
int u=path[i]; //u的后继结点v能到的点,u也能到达
f[u].set(u); //自己能到达自己
for (int v : g[u]) {
f[u].or(f[v]);
}
}
for (int i=1; i<=n; i++) System.out.println(f[i].cardinality());
}
}
public class Main{
public static void main(String[] args) throws IOException {
Solution s = new Solution();
s.init();
}
}