思路真恶心。
Source
https://www.lydsy.com/JudgeOnline/problem.php?id=2115
Solution
一看就是线性基,但看完题发现十分地不可做。
思路:随便选一条
1
1
到 的简单路径,那么任意一条路径都可以表示为:
选出的1到N的路径的xor和 xor 一个环的xor和 xor 另一个环的xor和 xor...
选
出
的
1
到
N
的
路
径
的
xor
和
xor
一
个
环
的
xor
和
xor
另
一
个
环
的
xor
和
xor...
也就是选出的 1 1 到 的简单路径的 xor xor 和异或上图中几个环的 xor xor 和。
于是,找出图中的所有环后,将所有环上边的异或和构成一个线性基,贪心求最大异或和。
同时,由于大的环可以看做多个小的环的异或,因此只需要找出图中所有小的环(即 dfs 出图的一棵生成树后,只包含一条非树边的环)
Code
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
#define Rof(i, a, b) for (i = a; i >= b; i--)
#define SpTree(u) for (int e = adj[u], v; e; e = nxt[e]) if (e != (frm[u] ^ 1))
using namespace std;
typedef long long ll; const int N = 5e4 + 5, M = 2e5 + 5, V = 65;
int n, m, ecnt = 1, nxt[M], adj[N], go[M], frm[N], tot; ll val[M], dis[N],
xo[V]; bool vis[N];
void add_edge(int u, int v, ll w) {
nxt[++ecnt] = adj[u]; adj[u] = ecnt; go[ecnt] = v; val[ecnt] = w;
nxt[++ecnt] = adj[v]; adj[v] = ecnt; go[ecnt] = u; val[ecnt] = w;
}
void ins(ll x) {
int i; Rof (i, 61, 0) if ((x >> i) & 1) {
if (xo[i] == -1) return (void) (xo[i] = x);
else x ^= xo[i];
}
}
ll maxor(ll orz) {
int i; Rof (i, 61, 0) if (xo[i] != -1 && (orz ^ xo[i]) > orz) orz ^= xo[i];
return orz;
}
void dfs(int u) {
vis[u] = 1; SpTree(u)
if (!vis[v = go[e]]) frm[v] = e, dis[v] = dis[u] ^ val[e], dfs(v);
else ins(dis[u] ^ dis[v] ^ val[e]);
}
int main() {
int i, u, v; ll w; cin >> n >> m; For (i, 1, m)
scanf("%d%d%lld", &u, &v, &w), add_edge(u, v, w);
For (i, 0, 61) xo[i] = -1; dfs(1); cout << maxor(dis[n]) << endl; return 0;
}