位运算
与 & 都为真为真
或 | 有一个为真就为真
非 ! 真的变假,假的变真
异或 ^ 如果相同为0,不同为1(相当于不进位加法, 1 + 0 = 1 , 0 + 1 = 1 , 1 + 1 = 0 , 0 + 0 = 0 ) ;
trick
数组初始化memset(f,0x3f,sizeof f) //这里会把一个每一个字节初始化为0x3f,,int的话对应的数是 0x3f3f3f3f
1,061,109,567 ,大概是int最大值的一半,一般情况下可以当做一个INF了
memset(h,-1,sizeof h) ; 由于-1的二进制是 1111,int的二进制是 1111111111111111,所以可以初始化
在处理数据的时候,会遇到题目中输到文件未结束 ,这时可以使用 scanf(“”) != EOF , 或者 ~ scanf(“”) ,因为EOF一般都被定义为-1,~ (-1) = 0 ,
在链式前星运算中 遍历边时循环结束条件就是 ~ i ,
在线段树时会用 n * 2 + 1 == n << 1 | 1 , n * 2 == n << 1,
左移运算符 <<
综上所述:1 << n == 2^n
右移运算符>>
综上所述: n >> x == n / (2^x)
状压思想
主要还是说bitset的应用
AcWing 164. 可达性统计
题意,分别统计每个点可以到达的点的个数
那么可以使用拓补排序,然后从后往前遍历,
一个点可以到达直接到达的点的 | ,这里使用bitset即可
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <iostream>
#include <bitset>
using namespace std;
const int N = 3e4 + 100 ;
int n,m;
int h[N],e[N],ne[N],idx;
int q[N],d[N] ;
bitset<N> f[N] ;
void add(int a,int b){
e[idx] = b , ne[idx] = h[a] , h[a] = idx++ ;
}
void topsort(){ // 拓补排序
int hh = 0 , tt = - 1 ;
for(int i = 1 ; i <= n ; i++){
if(!d[i]){
q[++tt] = i ;
}
}
while(hh <= tt){
int t = q[hh++] ;
for(int i = h[t] ; ~ i ; i = ne[i]){
int j = e[i] ;
if(-- d[j] == 0) q[++tt] = j ;
}
}
}
int main(){
cin >> n >> m ;
memset(h,-1,sizeof h) ;
while(m--){
int a,b;
cin >> a >> b;
add(a,b) ;
d[b] ++ ;
}
topsort() ;
for(int i = n -1 ; i >= 0 ; i --){
int j = q[i] ;
f[j][j] = 1 ;
for(int k = h[j] ; ~ k ; k = ne[k]){ //每个点的状态等于或上所有可到达的点
f[j] |= f[e[k]] ;
}
}
for(int i = 1 ; i <= n ; i++){
cout << f[i].count() << endl ;
}
return 0;
}