P4151 - 最大XOR和路径 题解
考虑
然后不难想到,
但是即使找到了这个生成空间的一个基的一个超集——简单环集合,但这还是太多了,简单环哪里能枚举的过来?考虑任意一棵生成树,一个结论是:非树边对应简单环的集合是基的一个超集。感觉上很对吧,就感觉生成树上的简单环能线性表出所有简单环,找不到反例对吧。但我们需要一个严谨的证明:每条非树边最多出现在一个树上简单环里对吧。对每个简单环的异或和,把所有非树边去掉,去掉的方式是异或上对应树上简单环,显然是可实现的。最后依然得到另一个简单环的异或和,而它没有非树边,只有树边,想仅由树边组成至少一个环是不可能的,所以必须是空集,那么原集合能被树上简单环线性表出就被证明了。
而且最后不需要真的求这个元素为边集的线性空间的一组基。最后要求的其实是,这个线性空间里每个元素的异或和得到的新线性空间(对边集取边权异或和显然是个线性变换)的一组基。那显然树上简单环的异或和集合是新线性空间的一组基,平移量也取对应异或和。可以选 dfs 树(其实其它生成树也可以,dfs 树只有返祖边比较舒服),树上简单环是
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define X first
#define Y second
#define pb push_back
#define mp make_pair
const int N=1000010;
int n,m;
vector<pair<int,int> > nei[N];
bool vis[N];
int xsm[N];
int b[N];
void insert(int x){
for(int i=60;~i;i--)if(x>>i&1)
if(b[i])x^=b[i];
else{b[i]=x;break;}
}
void dfs(int x=1,int fa=0){
vis[x]=true;
for(int i=0;i<nei[x].size();i++){
int y=nei[x][i].X,v=nei[x][i].Y;
if(y==fa){fa=-1;continue;}
if(!vis[y])xsm[y]=xsm[x]^v,dfs(y,x);
else insert(xsm[x]^xsm[y]^v);
}
}
signed main(){
cin>>n>>m;
while(m--){
int x,y,v;
scanf("%lld%lld%lld",&x,&y,&v);
nei[x].pb(mp(y,v)),nei[y].pb(mp(x,v));
}
dfs();
int res=xsm[n];
for(int i=60;~i;i--)if(res>>i&1)res^=b[i];
cout<<res;
return 0;
}