这题真的妙啊。
首先,我们不难发现,所有的复杂环都可以拆成若干个简单环异或的结果。所以我们只需考虑简单环即可。
引理:任意一条 1 到 n 的路径的异或和,都可以由任意一条 1 到 n 路径的异或和与图中的一些环的异或和来组合得到。
而对于含有两条以上 返祖边的 环,我们可以把他拆成 多个 只含有一条 返祖边的 异或和。所以dfs 找环的时候我们可以只考虑只含一条返祖边的环。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 50005;
const int maxm = 200005;
const int maxc = 2000001;
int tot=1,ver[maxm],he[maxn],ne[maxm];
LL w[maxm];
void add( int x,int y,LL _w ){
ver[++tot] = y;
ne[tot] = he[x];
he[x] = tot;
w[tot] = _w;
}
int vis[maxn];
const int base = 60;
LL b[base+1];
template <typename T>
void cal( T* a,int n ) {
for( int i = 0;i <= base;i++ ) b[i] = 0;
for (int i = 0; i < n; ++i) {
T x = a[i];
for (int j = base; j >= 0; --j) {
if (x >> j & (T)1) {
if (b[j]) x ^= b[j];
else {
b[j] = x;
for (int k = j - 1; k >= 0; --k) if (b[k] && (b[j] >> k & (T)1)) b[j] ^= b[k];
for (int k = j + 1; k <= base; ++k) if (b[k] >> j & (T)1) b[k] ^= b[j];
break;
}
}
}
}
}
LL a[maxc],ans,f[maxc];
int sz,n;
void dfs( int x,LL v,int e ){
vis[x] = 1;
f[x] = v;
if(x==n ) ans =v;
for( int cure = he[x];cure;cure =ne[cure] ){
if( (cure^1) == e ) continue;
int y = ver[cure];
if( vis[y] ){
a[sz++] = v^w[cure]^f[y];
}else{
dfs(y,v^w[cure],cure);
}
}
}
int main(){
int m;
scanf("%d%d",&n,&m);
for( int i = 1;i <= m;i++ ){
int x,y;LL w;scanf("%d%d%lld",&x,&y,&w);
add(x,y,w);add(y,x,w);
}
dfs(1,0,-1);
cal( a,sz );
for( int i = base;i >= 0;i-- ){
if( b[i] && !(ans >> i&1LL ) ){
ans ^= b[i];
}
}
printf("%lld\n",ans);
return 0;
}