[WC2011]最大XOR和路径「线性基+图论」

题目描述

这不是个链接

思路分析

谁推荐的题怎么全是新知识啊
如果你不会线性基,请出门左转学习这篇博客,然后切掉这道题【模板】线性基再回来看这道题。

  • 异或真是个神奇的东西!!!
  • 题目中要求路径必须是从 (1)(n) 的路径,然后显然这条路径不唯一,不仅如此,还会有环。
  • 首先从 (1) 进行 (dfs) 跑一遍简单路径,并在过程中找出所有的环。当然,不一定遍历到所有的环,但没遍历到的对答案没有影响,因为要求的是 (1)(n)
  • 考虑这些环可能依附简单路径的上,即可经过可不经过。这种情况很简单,用线性基判断一下经不经过就好了。还有一种情况就是因为一个环的出现而形成了多条简单路径(像钥匙扣一样)。这时候就可以利用异或的性质,因为我们 (dfs) 时已经求出了一条简单路径,那么我们用这个环异或一下这个路径就可以得到另一条路径,所以还是可以用线性基处理。
  • 最后在概述一下:先 (dfs) 求出到达 (n) 的简单路径的异或长度并找出途中的环,以简单路径的长度为初始答案,再用线性基拿所有的环长去更新答案就好了

(Code)

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define N 200010
#define R register
#define ll long long
using namespace std;
inline ll read(){
	ll x = 0,f = 1;
	char ch = getchar();
	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int n,m,head[N],tot;
ll circle[N],dis[N],p[N];
bool vis[N];
struct edge{
	int to,next;
	ll val;
}e[N<<2];
int len;
void addedge(int u,int v,ll w){
	e[++len].to = v;
	e[len].val = w;
	e[len].next = head[u];
	head[u] = len;
}
void dfs(int u,int fa){
	vis[u] = 1;
	for(R int i = head[u];i;i = e[i].next){
		int v = e[i].to;
		if(v==fa)continue;
		if(vis[v]){
			 circle[++tot] = dis[u]^dis[v]^e[i].val;//环长(指异或和)
			 continue;
		}
		dis[v] = dis[u]^e[i].val;
		dfs(v,u);
	}
}
void build(){
	for(R int i = 1;i <= tot;i++){//每个环进行一遍线性基处理
		for(R int j = 62;j>=0;j--){
			if(!(circle[i]>>j))continue;
			if(!p[j]){p[j]=circle[i];break;}
			circle[i] ^= p[j];
		}
	}
}
int main(){
	n = read(),m = read();
	for(R int i = 1;i <= m;i++){
		int x = read(),y = read();
		ll z = read();
		addedge(x,y,z),addedge(y,x,z);
	}
	dfs(1,0);
	build();
	ll ans = dis[n];
	for(R int i = 62;i>=0;i--){
		if((ans^p[i])>ans)ans ^= p[i];
	}
	printf("%lld
",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/hhhhalo/p/13856201.html