题目描述
给定一张N个点M条边的有向无环图,分别统计从每个点出发能够到达的点的数量。
输入格式
第一行两个整数N,M,接下来M行每行两个整数x,y,表示从x到y的一条有向边。
输出格式
输出共N行,表示每个点能够到达的点的数量。
数据范围
n,m∈【1,30000】。
样例:
in:
10 10
3 8
2 3
2 5
5 9
5 9
2 3
3 9
4 8
2 10
4 9
out:
1
6
3
3
2
1
1
1
1
1
题解
看到DAG先topsort一遍
统计答案时,观察易知每个点的答案的值等于它可以直接到达的点的答案的并集
那么可以考虑开个bitsit储存答案,每一位的01状态分别表示该点不可达到与可到达
其中bitset的.count可以直接统计1的个数
答案很容易就统计出来
代码
#include <cstdio>
#include <bitset>
#include <queue>
#define ll long long
using namespace std;
inline int read(){
int x=0,f=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') {x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return x*f;
}
const int maxn(3e4+5);
int n,m;
ll ans;
int head[maxn],cnt;
int d[maxn],tot,a[maxn];
bitset<maxn> f[maxn];
struct node{int next,to;}e[maxn<<1];
void add(int a,int b){
e[++cnt].to=b,e[cnt].next=head[a],head[a]=cnt,d[b]+=1;
}
void topsort(){
queue<int> q;
for (int i(1);i<=n;++i)
if (d[i]==0) q.push(i);
while (q.size()){
int u=q.front();
a[++tot]=u;
q.pop();
for (int i(head[u]);i;i=e[i].next){
int v=e[i].to;
d[v]-=1;
if (d[v]==0) q.push(v);
}
}
}
void init(){
n=read(),m=read();
for (int i(1),a,b;i<=m;++i) a=read(),b=read(),add(a,b);
}
void calc(){
for (int j(cnt);j;--j){//倒序枚举
int u=a[j];
f[u][u]=1;
for (int i(head[u]);i;i=e[i].next){
int v=e[i].to;
f[u]|=f[v];
}
}
}
void print(){
for (int i(1);i<=n;++i)
printf("%lld
",f[i].count());
}
signed main(){
init();
topsort();
calc();
print();
return 0;
}