题目:CH2101.
题目大意:给定一张
n
n
n个点
m
m
m条边的有向无环图,求每个点可以达到多少个点.
1
≤
n
,
m
≤
3
∗
1
0
4
1\leq n,m\leq 3*10^4
1≤n,m≤3∗104.
很容易想到先跑一个拓扑排序,从出度为 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)∈E⋃b[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;
}