[WC2011]最大XOR和路径

嘟嘟嘟


不愧是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;
}
原文地址:https://www.cnblogs.com/mrclr/p/10254307.html