P4151 [WC2011]最大XOR和路径 题解
题意很清楚就不说了。
\(Solution\)
看到重复的路径会重复计算异或和,再看到求异或最大值,能想到用线性基,那该怎么搞呢。

我们要从 \(1\) 号节点走到 \(8\) 号节点,我们首先要找到一条从 \(1\) 到 \(8\) 的链,是 \(1->2->7->8\)。
我们要让异或和最大,既然这是无向图,我们把环走一遍之后还能回来,所以我们走了之后就有可能异或和更大。
然后我们从 \(1\) 去到 \(8\),发现从 \(2\) 号上有一条出边指向一个环,我们从 \(2\) 走向了 \(3\),从 \(3\) 进入这个环,然后走一遍又出来,又经过了一遍 \(3\),于是我们发现 \(3\) 这条链是会经过 \(2\) 遍的,所以他的异或和会抵消掉,所以我们只需要考虑主链和环即可。
然后就转换成了求异或最大值的板子了。
我们把一个环的异或和放到线性基里,然后贪心的去找最大值即可。
/*
Work by: TLE_Automation
*/
#include<cmath>
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
#define int long long
using namespace std;
const int N = 1e6 + 10;
const int MAXN = 2e5 + 10;
inline char readchar() {
static char buf[100000], *p1 = buf, *p2 = buf;
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++;
}
inline int read() {
#define readchar getchar
int res = 0, f = 0;char ch = readchar();
for(; !isdigit(ch); ch = readchar()) if(ch == '-') f = 1;
for(; isdigit(ch); ch = readchar()) res = (res << 1) + (res << 3) + (ch ^ '0');
return f ? -res : res;
}
inline void print(int x) {
if (x < 0 ) putchar('-'), x = -x;
if (x > 9 ) print(x / 10);
putchar(x % 10 + '0');
}
struct node {int u, v, w, nxt;} e[MAXN];
int n, m, p[100], head[MAXN], cnt = 0, dis[MAXN], vis[MAXN];
void add(int u, int v, int w) {e[++cnt] = (node) {u, v, w, head[u]}, head[u] = cnt;}
void Insert(int x) {
for(int i = 63; i >= 0; i--) {
if(x & (1ll << i)) {
if(p[i]) x ^= p[i];
else { p[i] = x; break; }
}
}
}
void dfs(int u, int sum) {
vis[u] = 1, dis[u] = sum;
for(int i = head[u]; i; i = e[i].nxt) {
int v = e[i].v;
if(!vis[v]) dfs(v, dis[u] ^ e[i].w);
else Insert(dis[u] ^ dis[v] ^ e[i].w);
}
}
signed main() {
n = read(), m = read();
for(int i = 1, u, v, w; i <= m; i++) {
u = read(), v = read(), w = read();
add(u, v, w), add(v, u, w);
}
dfs(1, 0);
for(int i = 63; i >= 0; i--) dis[n] = max(dis[n], dis[n] ^ p[i]);
return printf("%lld\n", dis[n]), 0;
}

浙公网安备 33010602011771号