题解:【bzoj2115】[Wc2011] Xor(线性基)

这道题差不多是一道线性基的模板题。

如图,我们首先找到一条1到n的路径,这里是1-4-6。

然后考虑加入的环。

当加入的环在这个路径上时,例如加入环1-2-4-1,如图:

这个时候我们发现,我们加入这个环之后,我们的路径就变成了1-2-4-6,这条路径的异或和就等于原路径的异或和再异或这个环的所有边的异或和。

当加入的环不在原路径上时,例如加入环2-3-5-2,如图:

我们会发现加入这个环的时候,从原路径到这个环的这一条路径走了两次,所以可以不计,所以加入这个环之后的异或和还是等于原路径的异或和再异或这个环的所有边的异或和。

扫描二维码关注公众号,回复: 2721811 查看本文章

所以我们就可以找到一条路径,然后把所有的其它的环加入到线性基里,然后就可以求出答案了,具体请看代码。

#include<cstdio>
#include<cctype>
#include<cstring>
long long a[65],d[50010],val[200010];
int n,m,tot,vis[50010],head[50010],nxt[200010],to[200010];
int rdint(){
	int x=0;
	char c;
	do c=getchar();
	while(!isdigit(c));
	do{
		x=(x<<1)+(x<<3)+(c^48);
		c=getchar();
	}while(isdigit(c));
	return x;
}
long long rdll(){
	long long x=0;
	char c;
	do c=getchar();
	while(!isdigit(c));
	do{
		x=(x<<1ll)+(x<<3ll)+(c^48);
		c=getchar();
	}while(isdigit(c));
	return x;
}
void add_edge(int u,int v,long long w){
	nxt[++tot]=head[u];
	to[tot]=v;
	val[tot]=w;
	head[u]=tot;
	return;
}
void insert(long long x){
	for(int i=61;i>=0;i--)
		if(x&(1ll<<i)){
			if(!a[i]){
				a[i]=x;
				break;
			}
			x^=a[i];
			if(!x)
				break;
		}
	return;
}
long long getmax(long long ret){
	for(int i=61;i>=0;i--)
		if(!(ret&(1ll<<i)))
			ret^=a[i];
	return ret;
}
void dfs(int u,int fa){
	vis[u]=1;
	for(int i=head[u];~i;i=nxt[i]){
		int v=to[i];
		long long w=val[i];
		if(v==fa)
			continue;
		if(vis[v])
			insert(d[u]^d[v]^w);
		else{
			d[v]=d[u]^w;
			dfs(v,u);
		}
	}
	return;
}
int main(){
	memset(head,-1,sizeof(head));
	n=rdint();
	m=rdint();
	for(int i=1;i<=m;i++){
		int u=rdint(),v=rdint();
		long long w=rdll();
		add_edge(u,v,w);
		add_edge(v,u,w);
	}
	dfs(1,-1);
	printf("%lld",getmax(d[n]));
	return 0;
}

猜你喜欢

转载自blog.csdn.net/ezoiHQM/article/details/81213718