可达性统计
题目描述
给定一张 N 个点 M 条边的有向无环图,分别统计从每个点出发能够到达的点的数量。
输入格式
第一行两个整数 N,M,接下来 M 行每行两个整数 x,y,表示从 x 到 y 的一条有向边。
输出格式
输出共 N 行,表示每个点能够到达的点的数量。
数据范围
1≤N,M≤30000
输入样例:
10 10
3 8
2 3
2 5
5 9
5 9
2 3
3 9
4 8
2 10
4 9
输出样例:
1
6
3
3
2
1
1
1
1
1
Solution:
由于 DAG,考虑按照拓扑排序的逆序进行DP,
设 \(f[i]\) 表示节点 \(i\) 能到达的点的集合,
\[f[i]={i} | f[v](v为u的子节点)
\]
Code:
#include <iostream>
#include <algorithm>
#include <cstring>
#include <bitset>
using namespace std;
typedef pair<int,int> PII;
const int N=30005,INF=0x3f3f3f3f;
int n,m,cnt;
int idx,h[N];
int d[N],s[N],q[N];
bitset<N> f[N];
struct node
{
int nxt,to;
}e[N];
void add(int nxt,int to)
{
e[++idx].nxt=h[nxt];
e[idx].to=to;
h[nxt]=idx;
}
void top()
{
int hh=0,tt=-1;
for(int i=1;i<=n;++i)
if(d[i]==0)
q[++tt]=i;
while(hh<=tt)
{
int u=q[hh++];
s[++cnt]=u;
for(int i=h[u];~i;i=e[i].nxt)
{
int v=e[i].to;
if(--d[v]==0)q[++tt]=v;
}
}
}
int main()
{
cin>>n>>m;
memset(h,-1,sizeof h);
for(int i=0;i<m;++i)
{
int a,b;
cin>>a>>b;
add(a,b);
++d[b];
}
top();
for(int i=cnt;i>=1;--i)
{
int u=s[i];
f[u][u]=1;
for(int j=h[u];~j;j=e[j].nxt)
f[u]|=f[e[j].to];
}
for(int i=1;i<=n;++i)
cout<<f[i].count()<<endl;
return 0;
}

浙公网安备 33010602011771号