D150 拓扑排序+bitset P10480 可达性统计
D150 拓扑排序+bitset P10480 可达性统计_哔哩哔哩_bilibili
给定一张 N 个点 M 条边的有向无环图,分别统计从每个点出发能够到达的点的数量。
思路
有向无环图,当然是跑拓扑排序,怎样记录可达点的数量?
拓扑排序具有向后累计的特点,所以要建反图,这样终点能累计多少,说明它做起点就能到达多少

如果每个点开一个 $int$ 数组来计数的话,会重复统计。解决方法, 每个点开一个 $bitset$ 数组来计数
例如,$f[1]=(001 11010)_2,f[4]=(001 11000)_2$,说明 $1$ 可达 $1,3,4,5$,$4$ 可达 $3,4,5$
$bitset$ 可以用或运算去重,可以用 $cout$ 方法统计含 $1$ 的个数
相关板子:
// 拓扑排序+bitset O(n) #include<bits/stdc++.h> using namespace std; const int N=30010; int n,m,rd[N]; vector<int> e[N]; bitset<N> f[N]; //f[i]表示i这个点的可以抵达点的数量,即二进制中1的个数 void topo(){ queue<int> q; for(int i=1; i<=n; i++) if(!rd[i]) q.push(i); while(!q.empty()){ int u=q.front(); q.pop(); f[u][u]=1; //点u的第u位赋1,表示可以到达自己 for(auto v:e[u]){ f[v]|=f[u]; //非重复统计用并集运算 if(--rd[v]==0) q.push(v); } } } int main(){ scanf("%d%d",&n,&m); for(int i=0,x,y; i<m; i++){ scanf("%d%d",&x,&y); e[y].push_back(x); //建反图 rd[x]++; //记录入度 } topo(); for(int i=1; i<=n; i++) printf("%d\n",f[i].count()); }
浙公网安备 33010602011771号