https://www.luogu.com.cn/problem/P4151
题意概述:给定一张无向有权连通图,求从 $1$ 到 $n$ 的路径中,所有边权异或和最大的路径。
首先选择任意一条从 $1$ 到 $n$ 的简单路径,在这条路径上,从任意节点出发找到环遍历并返回,异或和只变化环上的异或和(因为去找环的这条路径走了两次,无贡献)。因此可以在这条 $1$ 到 $n$ 的简单路径上,任意异或上所有环的异或和,这部分相当于选数异或,线性基处理即可。
另外解释一下简单路径可以任意选的原因。假如从 $1$ 到 $n$ 有两条不同的路径,我们选择了一条更劣的路径,显然这两条路径整体成环,会被放入线性基计算,因此选哪条都是无所谓的。
具体实现上,从 $1$ 开始遍历整张图,维护路径上的异或和,考虑一条边 $[u,v,w]$,如果 $v$ 被访问过了,该边为返祖边,就把 $xr[u] \oplus xr[v] \oplus w$ 插入到线性基,否则继续遍历即可。遍历完成后,贪心求 $xr[u]$ 异或上线性基中元素能获得的最大值即可。
//author:kzssCCC#include <bits/stdc++.h>
using namespace std;
using ll = long long;void solve(){int n,m;cin >> n >> m;vector<vector<pair<ll,int>>> adj(n+1);for (int i=0;i<m;i++){int u,v;ll w;cin >> u >> v >> w;adj[u].emplace_back(w,v);adj[v].emplace_back(w,u);}vector<ll> xr(n+1,-1);xr[1] = 0;vector<ll> f(64,0);auto insert = [&](ll v){for (int i=63;i>=0;i--){if (v>>i&1){if (f[i]==0){f[i] = v;return;}v^=f[i];}}};function<void(int,int)> dfs = [&](int u,int par){for (auto& [w,v]:adj[u]){if (v==par) continue;if (xr[v]==-1){xr[v] = xr[u]^w;dfs(v,u);}else{insert(xr[u]^w^xr[v]);}}};dfs(1,-1);ll res = xr[n];for (int i=63;i>=0;i--){if ((res^f[i])>res){res^=f[i];}}cout << res << '\n';
}int main(){ios::sync_with_stdio(false);cin.tie(0);int t = 1;// cin >> t;while (t--) solve();return 0;
}
