蓝书(算法竞赛进阶指南)刷题记录——CH2101可达性统计(拓扑排序+bitset)

题目:CH2101.
题目大意:给定一张 n n n个点 m m m条边的有向无环图,求每个点可以达到多少个点.
1 ≤ n , m ≤ 3 ∗ 1 0 4 1\leq n,m\leq 3*10^4 1n,m3104.

很容易想到先跑一个拓扑排序,从出度为 0 0 0的点开始逆推回来.

但是直接求和很明显会有重复,所以考虑每个点 i i i记录一个集合 b [ i ] b[i] b[i]表示 i i i可以到达这个集合里的数.

那么显然:
b [ x ] = ⋃ ( x , y ) ∈ E b [ y ] b[x]=\bigcup_{(x,y)\in E}b[y] b[x]=(x,y)Eb[y]

然后用bitset实现这个集合即可,时间复杂度 O ( n ( n + m ) 32 ) O(\frac{n(n+m)}{32}) O(32n(n+m)),空间复杂度 O ( n 2 8 ) O(\frac{n^2}{8}) O(8n2).

代码如下:

#include<bits/stdc++.h> 
  using namespace std;

#define Abigail inline void
typedef long long LL;

const int N=30000;

struct side{
  int y,next;
}e[N+9];
int lin[N+9],top,n,m;

void ins(int x,int y){
  e[++top].y=y;
  e[top].next=lin[x];
  lin[x]=top; 
}


int deg[N+9],ord[N+9],co,ans[N+9];
bitset<N+9>b[N+9];
queue<int>q;

void topsort(){
  for (int i=1;i<=n;++i)
    if (!deg[i]) q.push(i);
  while (!q.empty()){
    int t=q.front();q.pop();
    ord[++co]=t;
    for (int i=lin[t];i;i=e[i].next){
      --deg[e[i].y];
      if (!deg[e[i].y]) q.push(e[i].y); 
    }
  }
  for (int i=co;i>=1;--i){
    int t=ord[i];
    b[t][t]=1;
    for (int j=lin[t];j;j=e[j].next)
      b[t]|=b[e[j].y];
    ans[t]=b[t].count();
  }
}

Abigail into(){
  scanf("%d%d",&n,&m);
  int x,y;
  for (int i=1;i<=m;++i){
    scanf("%d%d",&x,&y);
    ins(x,y);++deg[y];
  }
}

Abigail work(){
  topsort();
}

Abigail getans(){
  for (int i=1;i<=n;++i)
    printf("%d\n",ans[i]);
}

int main(){
  into();
  work();
  getans();
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值