[WC2011]最大XOR和路径

时间:2022-07-20 21:08:32

嘟嘟嘟



不愧是WC的题,思维真的很妙(虽然代码特别简单)。



首先暴力找出所有路径肯定不行。

题中说可以经过重复的边,并且边权也会被计算多次。那么就是说,如果经过一条边再沿这条边回来,这条边的贡献就是0了。但是我们可以通过这条边到达别的路径上。更准确说,是到一个环上。

于是就有这么一个做法:先找出所有环的亦或和,都扔到线性基里,然后任选一条从1到n的路径\(dis[n]\),把\(dis[n]\)和线性基亦或,得到的最大值就是答案。

代码特别简单。

#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
#define enter puts("")
#define space putchar(' ')
#define Mem(a, x) memset(a, x, sizeof(a))
#define In inline
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-8;
const int maxn = 5e4 + 5;
const int maxm = 1e5 + 5;
const int maxN = 63;
inline ll read()
{
ll ans = 0;
char ch = getchar(), last = ' ';
while(!isdigit(ch)) {last = ch; ch = getchar();}
while(isdigit(ch)) {ans = (ans << 1) + (ans << 3) + ch - '0'; ch = getchar();}
if(last == '-') ans = -ans;
return ans;
}
inline void write(ll x)
{
if(x < 0) x = -x, putchar('-');
if(x >= 10) write(x / 10);
putchar(x % 10 + '0');
} int n, m;
struct Edge
{
int nxt, to; ll w;
}e[maxm << 1];
int head[maxn], ecnt = -1;
In void addEdge(int x, int y, ll w)
{
e[++ecnt] = (Edge){head[x], y, w};
head[x] = ecnt;
} ll p[maxN];
In void insert(ll x)
{
for(int i = maxN; i >= 0; --i) if((x >> i) & 1)
{
if(p[i]) x ^= p[i];
else {p[i] = x; return;}
}
} bool vis[maxn];
ll dis[maxn];
In void dfs(int now, ll sum)
{
vis[now] = 1; dis[now] = sum;
for(int i = head[now], v; i != -1; i = e[i].nxt)
if(!vis[v = e[i].to]) dfs(v, sum ^ e[i].w);
else insert(sum ^ dis[v] ^ e[i].w);
} int main()
{
Mem(head, -1);
n = read(); m = read();
for(int i = 1; i <= m; ++i)
{
int x = read(), y = read(); ll w = read();
addEdge(x, y, w); addEdge(y, x, w);
}
dfs(1, 0);
ll ans = dis[n];
for(int i = maxN; i >= 0; --i) if(!((ans >> i) & 1)) ans ^= p[i];
write(ans), enter;
return 0;
}