一.题目链接:

可达性统计

二.题目大意:

给定一张N个点M条边的有向无环图,分别统计从每个点出发能够到达的点的数量。

三.分析:

第一想法是暴搜。。。。(我是不是没救了)

T是肯定的了。。。

对于每个点 x,他所能到达的点的个数 == y 能到达点的个数 + 1,其中存在 x 到 y 的有向边.

那么,我们可以先拓扑排序,得到拓扑序列,之后倒序遍历,统计个数即可.

统计时,可用 bitset 统计,按位与之后所得到的即为 x 点能到达的点.

四.代码实现:

#include <set>
#include <map>
#include <ctime>
#include <queue>
#include <cmath>
#include <stack>
#include <bitset>
#include <vector>
#include <cstdio>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define eps 1e-8
#define lc k * 2
#define rc k * 2 + 1
#define pi acos(-1.0)
#define ll long long
#define ull unsigned long long
using namespace std;

const int M = (int)3e4;
const int mod = 99991;
const int inf = 0x3f3f3f3f;

int u, v, w;
int n, m, cnt = 1;
int head[M + 5];
struct node
{
    int u, v, nx;
}Edge[M + 5];

int in[M + 5];
vector <int> path;
bitset <M + 5> bt[M + 5];

void add()
{
    scanf("%d %d", &u, &v);
    Edge[cnt].u = u;
    Edge[cnt].v = v;
    Edge[cnt].nx = head[u];
    head[u] = cnt++;
    in[v]++;
}

void topo()
{
    queue <int> q;
    for(int i = 1; i <= n; ++i)
    {
        if(!in[i])
            q.push(i);
    }
    while(!q.empty())
    {
        u = q.front();
        q.pop();
        path.push_back(u);
        for(int i = head[u]; i; i = Edge[i].nx)
        {
            v = Edge[i].v;
            if(--in[v] == 0)
                q.push(v);
        }
    }
}

int main()
{
    scanf("%d %d", &n, &m);
    while((m--) > 0)
        add();
    topo();
    for(int i = path.size() - 1; i >= 0; --i)
    {
        u = path[i];
        bt[u][u] = 1;
        for(int j = head[u]; j; j = Edge[j].nx)
        {
            v = Edge[j].v;
            bt[u] |= bt[v];
        }
    }
    for(int i = 1; i <= n; ++i)
        printf("%d\n", bt[i].count());
    return 0;
}