【题解】Acwing228. 异或

Acwing228. 异或

( ext{Solution:})

第一次见的套路 记录一下

首先观察到路径,而且 (n) 很大,往最短路方面想,但是一个异或最大值就直接把最短路给干掉了

考虑什么东西可以维护形如 选出一些数使得异或和最大 的问题?——线性基。

那么重新分析题目,我们被要求找到一条路径满足异或和最大,而我们不知道如何决策是最优的……

考虑分析一下最优答案的状态。我们发现,所有可能构成的答案的路径的并集中,必定有环。因为它们的起点终点都一样。

而环又有什么性质?显然可以来回走对吧。这就让我们想起了对应于线性基上选不选的决策。

那么,环现在是唯一自由的因素了。我们现在被要求选出一些数使得 (1) 可以通过它们到达 (n) 并且异或和最大化。

而所有路径都会形成环,也就是说,每条路径都可以通过 异或上一个环 来转化为其他路径

那这不就和用线性基维护环权值配对了吗。所以只需要 (dfs) 找环加上线性基维护贪心即可。

复杂度 (O(nlog n)) 注意代码里面直接把线性基消成对角矩阵了。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=4e5+10;
inline int read(){
	int s=0;
	char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();}
	return s;
}
int n,m,head[N],tot;
struct E{int nxt,to,dis;}e[N];
int val[N],vis[N];
struct Line_Base{
	int p[62];
	void insert(int x){
		for(int i=61;~i;--i){
			int v=x>>i&1;
			if(!v)continue;
			if(p[i])x^=p[i];
			else{
				p[i]=x;
				for(int j=i-1;~j;--j)if(p[i]>>j&1)p[i]^=p[j];
				for(int j=61;j>i;--j)if(p[j]>>i&1)p[j]^=p[i];
				return;
			}
		}
	}
	int query(int v){
		for(int i=61;~i;--i)if((v^p[i])>v)v^=p[i];
		return v;
	}
}U;
inline void link(int x,int y,int w){e[++tot]=(E){head[x],y,w};head[x]=tot;}
void dfs(int x){
	vis[x]=1;
	for(int i=head[x];i;i=e[i].nxt){
		int j=e[i].to;
		if(!vis[j]){
			val[j]=val[x]^e[i].dis;
			dfs(j);
		}
		else{
			int v=val[x]^val[j]^e[i].dis;
			if(!v)continue;
			U.insert(v);
		}
	}
}
signed main(){
	freopen("in.txt","r",stdin);
	n=read();m=read();
	for(int i=1;i<=m;++i){
		int x=read(),y=read(),z=read();
		link(x,y,z);link(y,x,z);
	}
	dfs(1);
	printf("%lld
",U.query(val[n]));
	return 0;
}
原文地址:https://www.cnblogs.com/h-lka/p/15378550.html