[WC2011]最大XOR和路径 解题报告

给出一个无向图,求出从 \(1\)\(n\) 的路径的边权异或值最大值,重复经过重复异或。

去学了一下线性基,发现还挺好用的。

如果不会,请左转线性基学习笔记。

可以发现,如果两次经过一条边,那么那条边对答案没有影响。

那么如果在目前的路径上从一点跑到另外一点,然后从这个点跑一个环,再原路返回,只会将答案异或上那个环的异或值。

如果将环的异或值都单独拉出来,然后再随便找一条从 \(1\)\(n\) 的路径,变成这条路径的异或值再异或上部分环的异或值使其最大,就转化为了线性基模型了。

当然不用找出所有的环,那样复杂度太劣了,只用找出一部分环,使其他的环的异或值都可以通过那些环的异或值异或出来,这个跑一遍 \(dfs\) 就行了。

可以分两种情况:

  1. 环内无环,此时这个环必然被dfs找到。

  2. 环内套环(称这种环为复合环),此时这个环可以被分成一个复合环和一个非复合环(或两个非复合环,即分到底),而这两个环我们已经考虑了(任意复合环有限次分割后必然得到若干非复合环,非复合环(即情况1)已经被考虑。)

#include<bits/stdc++.h>
using namespace std;

#define int long long
const int M=1e5+5;

int n,m;
int read(){
	int x=0,y=1;char ch=getchar();
	while(ch<'0'||ch>'9') y=(ch=='-')?-1:1,ch=getchar();
	while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
	return x*y;
}

int tot=0,first[M];
struct Edge{
	int nxt,to,w;
}e[M<<1];
void add(int x,int y,int z){
	e[++tot]=(Edge){first[x],y,z};
	first[x]=tot;
}

int p[M];
void insert(int x){
	for(int i=63;i>=0;i--){
		int c=(x>>i)&1;
		if(!c) continue ;
		if(p[i]) x^=p[i];
		else return (void)(p[i]=x);
	}
}

int query(int x){
	for(int i=63;i>=0;i--){
		int c=(x>>i)&1;
		if(c||!p[i]) continue ;
		x^=p[i];
	}
	return x;
}

int dis[M];bool vis[M];
void dfs(int u,int fa){
	vis[u]=1;
	for(int i=first[u];i;i=e[i].nxt){
		int v=e[i].to,w=e[i].w;
		if(v==fa) continue ;
		if(vis[v]) insert(dis[v]^dis[u]^w);
		else dis[v]=dis[u]^w,dfs(v,u);
	}
}

void solve(){
	n=read(),m=read();
	for(int i=1;i<=m;i++){
		int x=read(),y=read(),z=read();
		add(x,y,z),add(y,x,z);
	}
	dfs(1,0);
	printf("%lld\n",query(dis[n]));
}

signed main(){
	solve();
}
posted @ 2020-08-11 23:48  Dabuliuzp  阅读(127)  评论(0编辑  收藏  举报
/* */ 返回顶端