好久都没有更过知识点了

  • 引入:(可以跳过)
    首先可以看一下这道题(高斯消元会的情况下):
    然后就会有一个的概念(虽然我也不能太理解)。
  • 概念:(解决异或问题)
    不过线性基就是给定原数列,构建一个新数列,满足原数列的异或和集合=新数列的异或和集合,而且新数列大小尽量小。
  • 性质:
    1.集合里按照\(base[0……log_2n]\)存储,bs[i]如果不为0,它的最高位一定是\(2^i\)
    2.理解:每个insert(y)结束后y都会变为0(说明其中肯定能异或出y)
    3.集合里没有异或和为0的数,判断有没有0可以用性质2
  • code
    1.插入值:
bool Insert(int y) {
	for(int i=60;i>=0;i--) {
		if((y>>i)&1) {
			if(!Bs[i]){Bs[i]=y;return;}    //找到了就return,不要忘了
			else y^=Bs[i];
		}
	}
}

2.与k异或最大

ll Mx(ll k) {
	for(int i=60;i>=0;i--) {
		bool val=(k>>i)&1;
		if(!val) {k^=Bs[i];}
	}
	return k;
}

3.任意异或最大值

int mx=0;
for(int i=up;i>=0;i--) {
	if((mx>>i)&1) continue;
	mx^=Bs[i];
}

ps.最小值就先判断有没有异或和=0的,没有就最低位的大于0的bs[i]。
4.第k大
转化为D[]类线性基,性质:
1.\(2^i\)(第i位)只会在一个D[]的值中存在
2.两个bs[]异或起来一定会大于其中任意一个的值
操作方法,枚举每个bs[i]的每一位,如第j位为1,就看bs[j]>0吗。最后再(把有值的)离散化一下。
所以会发现第k大,刚好就是它二进制位i为1的的Bs[i]异或和。
证明?感性:k=1时就是\((1)_2\),k=2时显然\((10)_2\)每次你都会+1。
理性:\(f((k+1)_2)>f((k)_2)\)单调性可以证明,因为性质1,只要找到第一个字典序严格大于的二进制位置就可以高低立判了。
ps.还需判断0

void re_build() {
	for(int i=60;i>=0;i--) {
		for(int j=i-1;j>=0;j--) {
			if((Bs[i]>>j)&1) Bs[i]^=Bs[j];
		}
	}
	for(int i=0;i<=60;i++)if(Bs[i])D[cnt++]=Bs[i];
}

补充:线性基求异或最短路

最后的路径一定是多个环和一条链连在一起的情况。
初始选择任意一条\(S\)\(T\)的链,都能通过异或上若干环得到所有可能的情况。(证明:两条路径可以通过异或上两条路径共同的环相互转换,所以可以先得到路径,然后之后得到套的环直接加上去即可)
思路就转化为:随便找一条路径,然后求任意异或上环所得的最大值,找到每个环存在线性基里即可。找环可以用带权并查集或者dfs。(并查集做法可以结合可撤销联合出题

  • code
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
const int M=61;
typedef long long ll;
int fa[N],n,m,nxt[N],to[N],head[N],ecnt;
ll dis[N],len[N],Bs[M],fs[N];
bool vis[N];
void Insert(ll y) {
	if(!y)return;
	for(int i=60;i>=0;i--) {
		if((y>>i)&1) {
			if(!Bs[i]){Bs[i]=y;return;}
			else y^=Bs[i];
		}
	}
}
ll Mx(ll k) {
	for(int i=60;i>=0;i--) {
		bool val=(k>>i)&1;
		if(!val) {k^=Bs[i];}
	}
	return k;
}
void add_edge(int u,int v,ll w) {nxt[++ecnt]=head[u];to[ecnt]=v;len[ecnt]=w;head[u]=ecnt;}
int g_fa(int u) {
	if(u==fa[u])return u;
	int fx=g_fa(fa[u]);
	fs[u]^=fs[fa[u]];
	return fa[u]=fx;
}
void fd_Rd() {
	for(int i=1;i<=n;i++)fa[i]=i,fs[i]=0;
	for(int u=1;u<=n;u++) for(int j=head[u];j;j=nxt[j]) {
		int v=to[j];
		int fx=g_fa(u),fy=g_fa(v);
		if(fx==fy) {Insert(len[j]^fs[u]^fs[v]);}
		else {fa[fx]=fy;fs[fx]=fs[v]^len[j]^fs[u];}
	}
}
queue<int> Q;
void BFS(int s) {
	Q.push(s);vis[s]=1;
	while(!Q.empty()) {
		int u=Q.front(); Q.pop();
		for(int i=head[u];i;i=nxt[i]) {
			int v=to[i];
			if(vis[v])continue;vis[v]=1;
			dis[v]=dis[u]^len[i];Q.push(v);
		}
	}
}
int main() {
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++) {int u,v;ll w;scanf("%d%d%lld",&u,&v,&w);add_edge(u,v,w),add_edge(v,u,w);}
	fd_Rd();
	BFS(1);
	printf("%lld\n",Mx(dis[n]));
	return 0;
}