Luogu 4151 [WC2011]最大XOR和路径
你谷又乱评分……
首先发现答案只有可能是从$1$开始走到$n$,中间绕若干个环,然后使它取到的异或值最大。
这样子的话我们可以随便先取一条路径,强制选择走这条路径,然后把所有的环都丢进线性基里面去,因为如果要选择一个环,我们从路径中的一个点走出去然后在这个环上绕几圈然后走回来,发现中间这个“走出去”,“走回来”的过程中的点被异或了两遍,相当于不产生贡献。
其实就是搜一遍的事情。
时间复杂度$O(nlogn)$。
Code:
#include <cstdio> #include <cstring> using namespace std; typedef long long ll; const int N = 5e4 + 5; const int M = 2e5 + 5; int n, m, tot = 0, head[N]; ll dis[N]; bool vis[N]; struct Edge { int to, nxt; ll val; } e[M]; inline void add(int from, int to, ll val) { e[++tot].to = to; e[tot].val = val; e[tot].nxt = head[from]; head[from] = tot; } template <typename T> inline void read(T &X) { X = 0; char ch = 0; T op = 1; for(; ch > '9' || ch < '0'; ch = getchar()) if(ch == '-') op = -1; for(; ch >= '0' && ch <= '9'; ch = getchar()) X = (X << 3) + (X << 1) + ch - 48; X *= op; } inline void chkMax(ll &x, ll y) { if(y > x) x = y; } namespace Lp { ll p[70]; inline void ins(ll val) { for(int i = 63; i >= 0; i--) { if((val >> i) & 1) { if(!p[i]) { p[i] = val; break; } val ^= p[i]; } } } inline ll query(ll res) { for(int i = 63; i >= 0; i--) chkMax(res, (res ^ p[i])); return res; } } using namespace Lp; void dfs(int x) { for(int i = head[x]; i; i = e[i].nxt) { int y = e[i].to; if(!vis[y]) { vis[y] = 1; dis[y] = dis[x] ^ e[i].val; dfs(y); } else ins(dis[x] ^ dis[y] ^ e[i].val); } } int main() { read(n), read(m); for(int x, y, i = 1; i <= m; i++) { read(x), read(y); ll v; read(v); add(x, y, v), add(y, x, v); } dfs(1); printf("%lld\n", query(dis[n])); return 0; }