推荐博客 : https://www.cnblogs.com/vb4896/p/6149022.html
https://blog.csdn.net/qaq__qaq/article/details/53812883
这个我觉得不是很好理解,花了一天半得时间,稍微懂了一点,写个博客
首先我们要明确这个线性基可以解决什么样得问题,例如动态增加元素,求解集合异或最大值
这里有一个增加操作,向里面增加一个元素,从最高位向下扫,当扫到 1 ,并且线性基中该位置为 0 ,则将这个元素加入到线性基中,否则用此元素去异或线性基中的数
int val[maxn][40];
void insert(int b[], int x){
for(int i = 30; i >= 0; i--){
if (x>>i&1){
if (!b[i]) {b[i] = x; break;}
else x ^= b[i];
}
}
}
合并
void unit(int x,int y){
// 将 x 暴力插入到 y 中
for(int i=30;i>=0;--i)
if(val[x][i]) insert (val[y],val[x][i]);
}
查询
查询一个元素是否再集合中x

最大值
从高位到低位去扫一遍
int cal(int p){
int ans = 0;
for(int i = 30; i >= 0; i--){
if ((ans^val[i]) > ans) {
ans ^= val[i];
}
}
return ans;
}
最小值
int query(){
for(int i = 0; i <= 30; i++){
if (val[i]) return val[i];
}
return 0;
}
求解第K大
将线性基重新构造一下
ll cnt = 0;
ll p[65];
void rbuild(){
for(ll i = 60; i >= 0; i--){
for(ll j = i-1; j >= 0; j--){
if ((1ll<<j)&a[i]) a[i] ^= a[j];
}
}
for(ll i = 0; i <= 60; i++){
if (a[i]) p[cnt++] = a[i];
}
}
ll query(ll x){
if (x >= (1ll<<cnt)) return -1;
ll ans = 0;
for(ll j = 60; j >= 0; j--){
if ((1ll<<j)&x){
ans ^= p[j];
}
}
return ans;
}