拓扑排序+
S
T
L
(
b
i
t
s
e
t
)
STL(bitset)
STL(bitset)
题解:
我们假设从节点
i
i
i出发,可以达到的点集为
S
=
s
1
,
.
.
.
.
.
.
s
n
S = {s_1,......s_n}
S=s1,......sn,那么我们要求节点
i
i
i可达的点数,其实就是
S
S
S中所有点可达的点数之和,表示为:
f
(
i
)
=
∑
i
=
1
n
f
(
s
i
)
f(i) = \sum_{i = 1} ^ nf(s_i)
f(i)=∑i=1nf(si)其中
f
(
i
)
f(i)
f(i)为从
i
i
i出发可以到达的总点数。
既然设计到到达顺序的问题,我们就自然想到了拓扑排序,对于某一条边
(
x
,
y
)
(x, y)
(x,y),在序列中肯定是
x
x
x出现在
y
y
y之前,所以我们可以从后往前遍历一遍拓扑序列, 统计答案即可。
统计的方法我们考虑:利用位运算的知识,把
f
(
x
)
f(x)
f(x)压缩成一个二进制数,那么对于二进制的第
i
i
i位,他的含义就是:若
p
o
s
i
=
1
pos_i = 1
posi=1,存在一条边从
x
x
x到
i
i
i,反之不存在这样的边。这样我们可以把
n
n
n个数的求和运算转化成
n
n
n个数的或运算,最后的答案就是这个二进制结果中1的个数。
AC代码:
#include <bits/stdc++.h>
#define ill __int128
#define ll long long
#define PII pair <ll,ll>
#define ull unsigned long long
#define me(a,b) memset (a,b,sizeof(a))
#define rep(i,a,b) for (int i = a;i <= b;i ++)
#define req(i,a,b) for (int i = a;i >= b;i --)
#define ios std :: ios :: sync_with_stdio(false)
const double Exp = 1e-9;
const int INF = 0x3f3f3f3f;
const int inf = -0x3f3f3f3f;
const ll mode = 1000000007;
const double pi = 3.141592653589793;
using namespace std;
const int maxn = 3e4 + 5;
int n, m, head[maxn], deg[maxn], cnt, num, A[maxn];
bool flag[maxn];
queue<int > q;
bitset<maxn> bit[maxn];
struct Edge //前向星存边
{
int to, next;
}edge[maxn];
void add(int u, int v)
{
edge[++ cnt].to = v;
edge[cnt].next = head[u];
head[u] = cnt;
deg[v] ++;
return ;
}
void topsort()
{
for (int i = 1;i <= n;i ++) {
if (deg[i] == 0) q.push(i);
}
while (!q.empty()) {
int x = q.front();
flag[x] = 1;
q.pop();
A[++ num] = x;
for (int i = head[x];~i;i = edge[i].next) {
int y = edge[i].to;
if (flag[y]) continue;
if (-- deg[y] == 0) q.push(y);
}
}
}
void solve()
{
topsort();
for(int i = num;i >= 1;i --) {
int x = A[i];
bit[x].reset();
bit[x][x] = 1;
for (int j = head[x];~j;j = edge[j].next) {
int y = edge[j].to;
bit[x] |= bit[y];
}
}
for (int i = 1;i <= n;i ++) printf ("%d\n",bit[i].count());
return ;
}
int main()
{
me (head, -1);
scanf ("%d%d", &n, &m);
for (int i = 1;i <= m;i ++) {
int u, v;
scanf ("%d%d",&u, &v);
add (u, v);
}
solve();
return 0;
}