题意:求带边权无向图上 \(1\)\(n\) 的异或最短路,可以重复经过某条边。

首先,我们考虑从 \(x\)\(y\) 的路径 \(A\),它的权值是 \(a\)。我们从路径中途的某个地方离开路径,来到一个地方,然后回到这个路径(因为路径的结尾是 \(y\),到 \(y\) 的路径一定会回到这个 \(A\))。

  • 如果离开和回到原先路径是同一个地方,那么我们考虑其行进的轨迹,一定是出发,到达一个环,走一遍环,回来。而因为到达环和从环回来的路径权值都被计算了两次,等于没有贡献。所有的贡献就是环上的异或和。

  • 如果回到路径在离开路径节点 \(u\) 之后的节点 \(v\),等于 \(u\)\(v\) 的路段不贡献, \(u\)\(v\) 的另一条路径贡献。但是这等价于把 \(a\) 异或上 \(u\rightarrow v\rightarrow u\) 的环的异或和。

  • 如果回到路径 \(v\) 在离开路径 \(u\) 之前,则 \(v\)\(u\) 的路径贡献两次等于不贡献,和前面是同一种情况。

我们发现,所有的贡献都是把一个环的异或和异或进总的贡献值。

那是不是所有的环都可以呢?很明显可以。我们先从 \(a\)\(b\),走一个环到 \(b\) 回到 \(a\),就是把这个环贡献上了,因为任意的环都是可到达的,所以任意的环都是可贡献的。

然后我们考虑如何计算所有的环。我们考虑 dfs,因为无向图的 dfs 生成树只有树边和返祖边,我们就可以利用这一点。然后如果是由两个小环拼成的大环,则可以直接等价于两个小环的异或和。那么我们就只需要考虑最基础的环——一条返祖边和它两端点之间的树边生成的环。

这样的环可以直接 dfs 求出,我们在 dfs 的同时记录当前节点到 \(1\) 的异或和,因为异或的性质,我们一旦发现 \(in queue\) 的点就直接把当前异或和和原节点异或和异或起来就是环上的结果。(因为从 \(1\) 到环的结果被异或了两次)然后我们把这个结果丢进线性基。

最后,找到一条 \(1\)\(n\) 的路径(就是 \(n\)\(1\) 的异或和),在线性基里查一下最大值。

如果最优结果不是这条路径怎么办呢?其实,假设两条路径 \(1\rightarrow a\rightarrow n\)\(1\rightarrow b\rightarrow n\),那么它们组合成一个环 \(1\rightarrow b\rightarrow n\rightarrow a\rightarrow 1\),这样的情况也被我们考虑进去了,不会遗漏,所以一开始随便选路径即可。

int n,m,a,b,c,vtt[100005],vis[100005],inq[100005],p[35];
vt<pii>vv[100005];
inline void ins(int x){
	per(j,0,30)if(x>>j&1){
		if(!p[j]){
			p[j]=x;
			return;
		}else x^=p[j];
	}
}
inline int mx(int x){
	int res=x;
	per(j,0,30)if((res^p[j])<res)res^=p[j];
	return res;
}
inline void dfs(int x,int p){
	inq[x]=1;vtt[x]=1;
	for(auto j:vv[x])if(j.first!=p){
		if(inq[j.first]){
			ins(vis[x]^vis[j.first]^j.second);
		}else if(!vtt[j.first]){
			vis[j.first]=vis[x]^j.second;
			dfs(j.first,x);
		}
	}inq[x]=0;
}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cin>>n>>m;
	rp(i,m){
		cin>>a>>b>>c;
		vv[a].pb({b,c});
		vv[b].pb({a,c});
	}vis[1]=0;
	dfs(1,0);
	cout<<mx(vis[n])<<endl;
	return 0;
}
//Crayan_r