D150 拓扑排序+bitset P10480 可达性统计

D150 拓扑排序+bitset P10480 可达性统计_哔哩哔哩_bilibili

 

P10480 可达性统计 - 洛谷

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

思路

有向无环图,当然是跑拓扑排序,怎样记录可达点的数量?

拓扑排序具有向后累计的特点,所以要建反图,这样终点能累计多少,说明它做起点就能到达多少

如果每个点开一个 $int$ 数组来计数的话,会重复统计。解决方法, 每个点开一个 $bitset$ 数组来计数

例如,$f[1]=(001 11010)_2,f[4]=(001 11000)_2$,说明 $1$ 可达 $1,3,4,5$,$4$ 可达 $3,4,5$

 $bitset$ 可以用或运算去重,可以用 $cout$ 方法统计含 $1$ 的个数

相关板子:

D01【模板】拓扑排序 - 董晓 - 博客园

 

// 拓扑排序+bitset O(n) 
#include<bits/stdc++.h>
using namespace std;

const int N=30010;
int n,m,rd[N];
vector<int> e[N];
bitset<N> f[N]; //f[i]表示i这个点的可以抵达点的数量,即二进制中1的个数

void topo(){
  queue<int> q;
  for(int i=1; i<=n; i++) if(!rd[i]) q.push(i);
  while(!q.empty()){
    int u=q.front(); q.pop();
    f[u][u]=1; //点u的第u位赋1,表示可以到达自己
    for(auto v:e[u]){
      f[v]|=f[u]; //非重复统计用并集运算
      if(--rd[v]==0) q.push(v);
    }
  }
}
int main(){
  scanf("%d%d",&n,&m);
  for(int i=0,x,y; i<m; i++){
    scanf("%d%d",&x,&y);
    e[y].push_back(x); //建反图
    rd[x]++; //记录入度
  }
  topo();
  for(int i=1; i<=n; i++) printf("%d\n",f[i].count());
}

 

posted @ 2026-05-02 18:34  董晓  阅读(84)  评论(0)    收藏  举报