「WC2011」最大XOR和路径 做题记录

利用了 xor 两次为 \(0\) 的性质。
假设我们已经有了一条路径,要将其拓展至一条新的路径并更新答案,一种可能的拓展是存在一个环与该路径相交,就能将环上路径取反。
再仔细想想,其实不与该路径相交的环也是可以拓展的对象,完全可以从路径上某个点出发,进入该环,绕一圈,沿相同路径回来,
这样做前往环的一部分路径的贡献是重复了的,因此为 \(0\)
观察这两种拓展,发现每次都可以将原本的路径异或上任意一个环。
相当于确定了一条路径之后,可以选择异或一些环,使异或和最大。可以用线性基搞定。
这条路径如何选择?
任意选即可,如果存在两条不同的路径,它们至少有两个点相交,所以一定存在环可以使两者相拓展。
那么直接把所有环的异或和扔到线性基里,加上任意一条 \(1\)\(n\) 的路径求一下基可表达的最大值即可。


#include<bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fd(i,a,b) for(int i=a;i>=b;--i)
#define ull unsigned long long
using namespace std;
const int N=5e4+10, M=1e5+10;
int n,m,tot,last[N];
bool bz[N];
struct edge{
	int st,en,next;ull v;
}E[M<<1];
ull t[100],ans,dis[N];
void add(int x,int y,ull z){
	E[++tot]=(edge){x,y,last[x],z};
	last[x]=tot;
}
void insert(ull x){
	fd(i,62,0)
		if(x&(1ll<<i))x^=t[i];
	if(x){
		fd(i,62,0)
			if(x&(1ll<<i)){
				t[i]=x;
				break;
			}
	}
}
void dfs(int x,int fr){
	bz[x]=1;
	for(int p=last[x];p;p=E[p].next){
		int y=E[p].en;
		if(y==fr)continue;
		if(bz[y]){
			insert(dis[y]^dis[x]^E[p].v);
		}else{
			dis[y]=dis[x]^E[p].v;
			dfs(y,x);
		}
	}
}
int main(){
	freopen("data.in","r",stdin);
	freopen("data.out","w",stdout);
	scanf("%d%d",&n,&m);
	fo(i,1,m){
		int x,y;ull z;
		scanf("%d%d%llu",&x,&y,&z);
		add(x,y,z);add(y,x,z);
	}
	dfs(1,0);
	ans=dis[n];
	fd(i,62,0){
		if(!(ans&(1ll<<i)))ans^=t[i];
	}
	printf("%llu\n",ans);

	return 0;
}
posted @ 2022-04-06 22:36  Kelvin2005  阅读(35)  评论(0)    收藏  举报