P10480 可达性统计
题目描述
给定一张 NNN 个点 MMM 条边的有向无环图,分别统计从每个点出发能够到达的点的数量。
输入格式
第一行两个整数 N,MN,MN,M,接下来 MMM 行每行两个整数 x,yx,yx,y,表示从 xxx 到 yyy 的一条有向边。
输出格式
输出共 NNN 行,表示每个点能够到达的点的数量。
输入输出样例 #1
输入 #1
10 10
3 8
2 3
2 5
5 9
5 9
2 3
3 9
4 8
2 10
4 9
输出 #1
1
6
3
3
2
1
1
1
1
1
说明/提示
测试数据满足 1≤N,M≤300001 \le N,M \le 300001≤N,M≤30000,1≤x,y≤N1 \le x,y \le N1≤x,y≤N。
对于这题,可以采用逆向拓扑排序,从出度为0的结点开始向前更新。利用bitset来进行集合的合并。若仅仅简单相加,会导致重复统计。
cpp
#include<bits/stdc++.h>
using namespace std;
int main(){
int n, m;
cin>>n>>m;
vector<bitset<30001>> dp(n+1);
vector<vector<int>> g(n+1);
vector<int> in_(n+1, 0);
vector<int> out_(n+1, 0);
priority_queue<int, vector<int>, greater<>> pq;
for(int i = 1;i<=m;i++){
int u, v;
cin>>u>>v;
g[v].push_back(u);
in_[v]++;
out_[u]++;
}
for(int i = 1;i<=n;i++){
if(!out_[i]){
pq.emplace(i);
}
dp[i][i] = 1;
}
while(!pq.empty()){
int v = pq.top();
pq.pop();
for(auto i : g[v]){
out_[i]--;
dp[i] |= dp[v];
if(!out_[i]){
pq.emplace(i);
}
}
}
for(int i = 1;i<=n;i++){
cout<<dp[i].count()<<'\n';
}
return 0;
}