[WC2011]最大XOR和路径 解题报告
给出一个无向图,求出从 \(1\) 到 \(n\) 的路径的边权异或值最大值,重复经过重复异或。
去学了一下线性基,发现还挺好用的。
如果不会,请左转线性基学习笔记。
可以发现,如果两次经过一条边,那么那条边对答案没有影响。
那么如果在目前的路径上从一点跑到另外一点,然后从这个点跑一个环,再原路返回,只会将答案异或上那个环的异或值。
如果将环的异或值都单独拉出来,然后再随便找一条从 \(1\) 到 \(n\) 的路径,变成这条路径的异或值再异或上部分环的异或值使其最大,就转化为了线性基模型了。
当然不用找出所有的环,那样复杂度太劣了,只用找出一部分环,使其他的环的异或值都可以通过那些环的异或值异或出来,这个跑一遍 \(dfs\) 就行了。
可以分两种情况:
-
环内无环,此时这个环必然被dfs找到。
-
环内套环(称这种环为复合环),此时这个环可以被分成一个复合环和一个非复合环(或两个非复合环,即分到底),而这两个环我们已经考虑了(任意复合环有限次分割后必然得到若干非复合环,非复合环(即情况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();
}