【二进制$bitset$计数 异或求并集】 可达性统计

传送门

题意

给定\(n\)个点\(m\)条边的有向无环图,统计从每个点出发所能到达的点的数量

数据范围

\(1 \leq N, M \leq 30000\)

题解

统计的是从\(x\)出发的后继能够到达的点的并集和其自身。
用一个二进制数表示当前节点可以到的节点,第 \(i\) 位为\(1\)就是可以到达
\(f[i]\)就表示 \(i\) 可达的点,计算出来一个拓扑序列,
按照拓扑序列的倒序算过来即可,开始的时候所有点只能到达自己,从拓扑序列的从后一个点开始算递推即可,最后一个数没有出边。
\(bitset\)开数组

Code

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<n;i++)
#define per(i,a,n) for(int i=n-1;i>=a;i--)

const int N=3e4+10;
struct node
{
   int to,ne;
}e[N];
int h[N],idx,deg[N],cnt;
int tops[N];
void add(int a,int b)
{
   e[++idx].to=b;
   e[idx].ne=h[a];
   h[a]=idx;
   deg[b]++;
}
int ans[N],n,m;
bitset<N>f[N];
void topsort()
{
   queue<int>q;
   rep(i,1,n+1) if(deg[i]==0) q.push(i);
   while(q.size())
   {
      int t=q.front();
      q.pop();
      tops[++cnt]=t;
      for(int i=h[t];i;i=e[i].ne)
      {
         int to=e[i].to;
         if(--deg[to] == 0) q.push(to);
      }
   }
}
void cal()
{
   per(i,1,cnt+1)
   {
      int t=tops[i];
      f[t][t]=1;
      for(int i=h[t];i;i=e[i].ne) f[t]|=f[e[i].to];
   }
}
int main()
{
   cin>>n>>m;
   while(m--)
   {
      int a,b;
      cin>>a>>b;
      add(a,b);
   }
   topsort();
   cal();
   rep(i,1,n+1) cout<<f[i].count()<<endl;
}
posted @ 2020-10-11 01:59  Hyx'  阅读(158)  评论(0)    收藏  举报