2101 可达性统计 0x20「搜索」例题
描述
给定一张N个点M条边的有向无环图,分别统计从每个点出发能够到达的点的数量。N,M≤30000。
输入格式
第一行两个整数N,M,接下来M行每行两个整数x,y,表示从x到y的一条有向边。
输出格式
共N行,表示每个点能够到达的点的数量。
样例输入
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
首先建立拓补图,之后倒着搜索拓补图,此时节点分别或一下所能达到的所有节点,最后记录一下1的个数,就是最后的答案
#include<cstdio>
#include<queue>
#include<bitset>
#include<cstring>
#include<iostream>
using namespace std;
const int N=3e4+10;
bitset<N>f[N];
int ans[N];
queue<int>q;
vector<int>v[N];
int in[N];
int main(){
std::ios::sync_with_stdio(false);
int n,m;
while(cin>>n>>m){
memset(ans,0,sizeof(ans));
memset(in,0,sizeof(in));
while(m--){
int a,b;
cin>>a>>b;
v[a].push_back(b);
in[b]++;
}
while(!q.empty())
q.pop();
for(int i=1;i<=n;i++)
if(in[i]==0)
q.push(i);
for(int i=1;i<N;i++)
f[i].reset();
int top=0;
while(!q.empty())
{
int now=q.front();
q.pop();
ans[top++]=now;
for(int i=0;i<v[now].size();i++)
{
in[v[now][i]]--;
if(in[v[now][i]]==0)
q.push(v[now][i]);
}
}
for(int i=top-1;i>=0;i--)
{
int now=ans[i];
f[now][now]=1;
for(int j=0;j<v[now].size();j++){
f[now]|=f[v[now][j]];
}
}
for(int i=1;i<=n;i++)
cout<<f[i].count()<<endl;
}
}