好神秘的题目。
看到异或和最大可以联想到 Trie 树?不对啊这题怎么 Trie 都不是很正经。
而这正是线性基擅长处理的问题类型。
发掘异或的性质:对于这张图上的环,我们一定可以任意决定它选或不选。
为什么?考虑先从起点 $1$ 开始搜一下 dfs 树,则非树边都是返祖边,且它和一部分树边构成环。
如果我们需要选一个环,可以考虑从 $1$ 开始,先到达环的顶部,然后沿着树边走到环底部,再通过返祖边绕回来,最后回到起点 $1$,此时产生的异或和就是环异或和。
但是需要 $1$ 走到 $n$,那就是 dfs 树上 $1 \to n$ 的异或和了。
求异或最大值,只需要把所有返祖边构成的环扔进线性基,查询 $dis_n$ 即树上异或和能构成的最大数。
#include <bits/stdc++.h>
using namespace std;
const int N = 5e4 + 5, M = N << 2;
struct BIT {
long long base[65];
bool chk(long long x, int i) { return (x >> i) & 1; }
void insert(long long x) {
for (int i = 60; i >= 0; i--) {
if (!chk(x, i)) continue;
if (!base[i]) return base[i] = x, void();
x ^= base[i];
}
}
long long query(long long x) {
for (int i = 60; i >= 0; i--) x = max(x, x ^ base[i]);
return x;
}
} bit;
int n, m, h[N], e[M], ne[M], idx = 0;
long long w[M], dis[N];
inline void add(int a, int b, long long c) { e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++; }
int fa[N];
bool st[N];
void dfs1(int u) {
st[u] = 1;
for (int i = h[u]; ~i; i = ne[i]) {
int v = e[i]; if (st[v]) continue;
dis[v] = dis[u] ^ w[i], fa[v] = u, dfs1(v);
}
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) h[i] = -1;
for (int i = 1; i <= m; i++) {
int a, b; long long c; scanf("%d%d%lld", &a, &b, &c);
add(a, b, c), add(b, a, c);
}
dfs1(1);
for (int u = 1; u <= n; u++) {
for (int i = h[u]; ~i; i = ne[i]) {
int v = e[i]; if (fa[v] == u) continue;
bit.insert(dis[u] ^ dis[v] ^ w[i]);
}
}
printf("%lld\n", bit.query(dis[n]) );
return 0;
}