📚【模板】线性基
性质
线性基是集合中的一个集合,有性质:
1.线性基中的元素相互异或,可以得到原集合的所有元素;
2.线性基是最小的满足性质1
的集合;
3.线性基没有异或和为\(0\)的子集;
4.线性基中每个元素的异或方案唯一,也就是说,线性基中不同的异或组合异或出的数都是不一样的;
5.线性基中每个元素的二进制最高位互不相同。
求线性基
void insert(long long _x) {
for(int i = 62;~i;--i) {
if(!(_x>>i))
continue;
if(bss[i]) {
_x ^= bss[i];
} else {
bss[i] = _x;
break;
}
}
}
解决异或和问题
1.集合最大异或和
\(\text{luogu P3812 【模板】线性基}\)
long long getmax() {
long long _res = 0;
for(int i = 62;~i;--i) {
if((_res^bss[i]) > _res)
_res ^= bss[i];
}
return _res;
}
2.集合最小异或和
小性质
对于一个集合\(B\),线性基为\(B_{bss}\),其子集的异或和每个数出现的次数相同,且为\(2^{\mid B\mid-\mid B_{bss}\mid}\)
线段树维护线性基
\(\textrm{bzoj 4184 shallot}\)
#include <stdio.h>
#include <map>
#include <vector>
#define llt long long int
const int N = 5e5+10;
std :: map<llt,int> refer;
std :: vector<llt> tree[N<<2];
#define lid(id) id<<1|1
#define rid(id) id<<1
llt shallot[N], fact[64];
int n;
struct BASE {
llt base[64];
void insert(llt x) {
for(int i = 62;~i;--i) {
if(x&fact[i]) {
if(base[i])
x ^= base[i];
else {
base[i] = x;
return;
}
}
}
}
llt query() {
llt res = 0;
for(int i = 62;~i;--i)
if(base[i]&&!(res&fact[i]))
res ^= base[i];
return res;
}
};
void insert(int id,int L,int R,int l,int r,int val) {
if(L > r||R < l)
return;
if(l <= L&&R <= r) {
tree[id].push_back(-val);
return;
}
int mid = (L+R)>>1;
if(l <= mid) insert(lid(id),L,mid,l,r,val);
if(r > mid) insert(rid(id),mid+1,R,l,r,val);
}
void dfs(int id,int L,int R,BASE b) {
for(auto i : tree[id])
b.insert(i);
if(L == R) {
printf("%lld\n",b.query());
return;
}
int mid = (L+R)>>1;
dfs(lid(id),L,mid,b);
dfs(rid(id),mid+1,R,b);
}
signed main() {
fact[0] = 1;
for(int i = 1;i <= 62;++i)
fact[i] = fact[i-1]<<1;
scanf("%d",&n);
for(int i = 1;i <= n;++i) {
scanf("%lld",&shallot[i]);
if(shallot[i] >= 0)
refer[shallot[i]] = i;
else {
insert(1,1,n,refer[-shallot[i]],i-1,shallot[i]);
refer[-shallot[i]] = 0;
}
}
for(int i = 1;i <= n;++i) {
if(shallot[i] > 0&&refer[shallot[i]])
insert(1,1,n,refer[shallot[i]],n,-shallot[i]);
}
dfs(1,1,n,BASE{});
}