📚【模板】线性基

性质

线性基是集合中的一个集合,有性质:

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{});
}

练习

\(\text{luogu P4570 [BJWC2011]元素}\)

\(\text{luogu P4869 albus就是要第一个出场}\)

posted @ 2022-07-25 10:48  bikuhiku  阅读(17)  评论(0编辑  收藏  举报