给定一张N个点M条边的有向无环图,分别统计从每个点出发能够到达的点的数量。
输入格式
第一行两个整数N,M,接下来M行每行两个整数x,y,表示从x到y的一条有向边。
输出格式
输出共N行,表示每个点能够到达的点的数量。
数据范围
1≤N,M≤300001≤N,M≤30000
输入样例:
10 10
3 8
2 3
2 5
5 9
5 9
2 3
3 9
4 8
2 10
4 9
输出样例:
1 6 3 3 2 1 1 1 1 1
题意分析:
题目已经说明白,给我们的是DAG(有向无环图)。既然是DAG,可以很容易的联想到拓扑排序。题目让我们统计每个点出发能到达的点的数量,我们可以先模拟一下样例,如下图(只例举出1,2,3三个点)。
题解:
综上所述,设从点 x 出发能够到达的点构成的集合是 f(x),从点 x 出发能够到达的点,是从 x 的各个后继节点 y 出发能够到达的点的并集,再加上点 x 自身 。
f(2) = f(3) ∪ f(5) ∪ f(10) = …
先按照拓扑排序算法求出拓扑序,然后按照拓扑序的倒叙进行计算------因为在拓扑序中,任意一条边 (x , y),x 都排在 y 之前。
关于状态压缩 bitset容器:
转载:https://oi-wiki.org/ds/stl/bitset/
介绍¶
std :: bitset 是标准库中的一个固定大小序列,其储存的数据只包含 0/1
众所周知,由于内存地址是按字节即 byte 寻址,而非比特 bit ,
我们一个 bool 类型的变量,虽然只能表示 0/1 , 但是也占了 1byte 的内存
bitset 就是通过固定的优化,使得一个字节的八个比特能分别储存 8 位的 0/1
对于一个 4 字节的 int 变量,在只存 0/1 的意义下, bitset 占用空间只是其
在某些情况下通过 bitset 可以使你的复杂度除以 32
当然, vector 的一个特化 vector<bool> 的储存方式同 bitset 一样,区别在于其支持动态开空间,
bitset 则和我们一般的静态数组一样,是在编译时就开好了的。
那么为什么要用 bitset 而非 vector<bool> ?
通过以下的介绍,你可以更加详细的看到 bitset 具备的方便操作
#include <bitset> // 包含 bitset 的头文件
运算符¶
operator[] : 访问其特定的一位
operator ==/!= : 比较两个 bitset 内容是否完全一样
operator &=/|=/^=/~ : 进行按位与/或/异或/取反操作
operator <</>>/<<=/>>= : 进行二进制左移/右移
operator <</>> : 流运算符,这意味着你可以通过 cin/cout 进行输入输出
vector<bool> 只具有前两项
成员函数¶
test() : 它和 vector 中的 at() 的作用是一样的,和 [] 运算符的区别就是越界检查
count() : 返回 true 的数量
set() : 将整个 bitset 设置成 true , 你也可以传入参数使其设置成你的参数
reset() : 将整个 bitset 设置成 false
flip() : 翻转该位 (0 变 1,1 变 0), 相当于逻辑非/异或 1
to_string() : 返回转换成的字符串表达
to_ulong() : 返回转换成的 unsigned long 表达 ( long 在 NT 及 32 位 POSIX 系统下与 int 一样,在 64 位 POSIX 下与 long long 一样)
to_ullong() C++11, 返回转换成的 unsigned long long 表达
这些 vector<bool> 基本都没有
作用¶
一般来讲,我们可以用 bitset 优化一些可行性 DP, 或者线筛素数 ( notprime 这种 bool 数组可以用 bitset 开到 之类的)
它最主要的作用还是压掉了内存带来的时间优化, 的常数优化已经可以是复杂度级别的优化了,比如一个 的 算法, 显然很卡,在常数大一点的情况下必然卡不过去,O(松)不能算!, 这时候如果我们某一维除以 32, 则可以比较保险的过了这道题
其实 bitset 不光是一个容器,更是一种思想,我们可以通过手写的方式,来把 long long 什么的压成每 bit 表示一个信息,用 STL 的原因更多是因为它的运算符方便
1 #include <iostream> 2 #include <cstring> 3 #include <bitset> 4 #include <algorithm> 5 #include <queue> 6 using namespace std; 7 int n,m; 8 const int maxn=3e4+5; 9 bitset<maxn> f[maxn]; 10 int h[maxn],e[maxn],ne[maxn],idx; 11 int seq[maxn],in[maxn]; 12 13 void add(int a,int b){ 14 e[idx]=b,ne[idx]=h[a],h[a]=idx++; 15 } 16 17 void topsort(){ 18 queue<int> que; 19 for(int i=1;i<=n;i++){ 20 if(in[i]==0) que.push(i); 21 } 22 int jishu=0; 23 while(!que.empty()){ 24 int top=que.front(); 25 que.pop(); 26 seq[jishu++]=top; 27 for(int j=h[top];~j;j=ne[j]){ 28 int ee=e[j]; //与其相连的那条边 29 if(--in[ee]==0) que.push(ee); 30 } 31 } 32 } 33 34 int main(){ 35 cin>>n>>m; 36 memset(h,-1,sizeof(h)); 37 for(int i=1;i<=m;i++){ 38 int d1,d2; 39 cin>>d1>>d2; 40 add(d1,d2); 41 in[d2]++; 42 } 43 topsort(); 44 for(int i=n-1;i>=0;i--){ 45 int j=seq[i]; 46 f[j][j]=1; 47 for(int k=h[j];~k;k=ne[k]){ 48 f[j]|=f[e[k]]; 49 } 50 } 51 for(int i=1;i<=n;i++){ 52 cout << f[i].count() << endl; 53 } 54 return 0; 55 }
1 #include <iostream> 2 #include <cstring> 3 #include <bitset> 4 #include <algorithm> 5 #include <queue> 6 using namespace std; 7 int n,m; 8 const int maxn=3e4+5; 9 bitset<maxn> f[maxn]; 10 int h[maxn],e[maxn],ne[maxn],idx; 11 int seq[maxn],in[maxn]; 12 13 void add(int a,int b){ 14 e[idx]=b,ne[idx]=h[a],h[a]=idx++; 15 } 16 17 void topsort(){ 18 queue<int> que; 19 for(int i=1;i<=n;i++){ 20 if(in[i]==0) que.push(i); 21 } 22 int jishu=0; 23 while(!que.empty()){ 24 int top=que.front(); 25 que.pop(); 26 seq[jishu++]=top; 27 for(int j=h[top];~j;j=ne[j]){ 28 int ee=e[j]; //与其相连的那条边 29 if(--in[ee]==0) que.push(ee); 30 } 31 } 32 } 33 34 int main(){ 35 cin>>n>>m; 36 memset(h,-1,sizeof(h)); 37 for(int i=1;i<=m;i++){ 38 int d1,d2; 39 cin>>d1>>d2; 40 add(d1,d2); 41 in[d2]++; 42 } 43 topsort(); 44 for(int i=n-1;i>=0;i--){ 45 int j=seq[i]; 46 f[j][j]=1; 47 for(int k=h[j];~k;k=ne[k]){ 48 f[j]|=f[e[k]]; 49 } 50 } 51 for(int i=1;i<=n;i++){ 52 cout << f[i].count() << endl; 53 } 54 return 0; 55 } 56 57 58 59 #include <iostream> 60 #include <cstring> 61 #include <bitset> 62 #include <algorithm> 63 #include <queue> 64 using namespace std; 65 int n,m; 66 const int maxn=3e4+5; 67 bitset<maxn> f[maxn]; 68 vector<int> G[maxn]; 69 int seq[maxn],in[maxn]; 70 71 void topsort(){ 72 queue<int> que; 73 for(int i=1;i<=n;i++){ 74 if(in[i]==0) que.push(i); 75 } 76 int jishu=0; 77 while(!que.empty()){ 78 int top=que.front(); 79 que.pop(); 80 seq[jishu++]=top; 81 for(auto X:G[top]){ 82 if(--in[X]==0) que.push(X); 83 } 84 } 85 } 86 87 int main(){ 88 cin>>n>>m; 89 for(int i=1;i<=m;i++){ 90 int d1,d2; 91 cin>>d1>>d2; 92 G[d1].push_back(d2); 93 in[d2]++; 94 } 95 topsort(); 96 for(int i=n-1;i>=0;i--){ 97 int j=seq[i]; 98 f[j][j]=1; 99 for(auto X:G[j]){ 100 f[j]|=f[X]; 101 } 102 } 103 for(int i=1;i<=n;i++){ 104 cout << f[i].count() << endl; 105 } 106 return 0; 107 108 109 }