可达性统计

题目描述

给定一张 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;
}
posted @ 2022-10-18 23:09  FighterQ  阅读(34)  评论(0)    收藏  举报