题目链接
题意:给你一个无向连通图,求一条从1到n的路径,使得路径上权值的异或和最大。
对于无向连通图,我们可以重复经过同一条路径多次。根据异或的性质,我们如果从这条路走过去再走回来,答案是不变的。
对于一个无向连通图,如果是一棵树,那么根据刚才的结论,答案就是1到n的这条链的异或和,因为走其他分支都要原路返回,两边异或后答案不变。那么只有图中的环会对答案产生影响。
我们来考虑在当前点走到任何一个环再走回来,答案的变化相当于异或上了环的异或和,因为不在环上的路径被经过了两边抵消掉了,所以我们最后的答案会是任意一条1到n的路径的异或和再异或上若干个环的异或和。任意选一条路径是因为如果有多条路径,那么意味着这条路径与其他路径形成了环,用环的异或和异或当前路径的异或和就是另一条路径的异或和,所以这里的路径可以任选。
最后用线性基求最大的解即可。
实现的话就是dfs一遍,然后在dfs的过程中维护路径的异或和并往要做线性基的集合插入元素。
代码:
#include <bits/stdc++.h>
using namespace std;
int n,m,hed[100010],cnt,vis[100010];
long long ans,dis[100010],xian[20000];
struct node
{
int to,next;
long long dis;
}a[200010];
void add(int from,int to,long long dis)
{
a[++cnt].to=to;
a[cnt].dis=dis;
a[cnt].next=hed[from];
hed[from]=cnt;
}
void insert(long long x)
{
for(int i=63;i>=0;--i)
{
if(x&(1LL<<i))
{
if(!xian[i])
{
xian[i]=x;
break;
}
else
x^=xian[i];
}
}
}
void dfs(int x)
{
for(int i=hed[x];i;i=a[i].next)
{
int y=a[i].to;
if(!vis[y])
{
dis[y]=dis[x]^a[i].dis;
vis[y]=1;
dfs(y);
}
else
insert(dis[x]^a[i].dis^dis[y]);
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;++i)
{
int x,y;
long long z;
scanf("%d%d%lld",&x,&y,&z);
add(x,y,z);
add(y,x,z);
}
dfs(1);
ans=dis[n];
for(int i=63;i>=0;--i)
ans=max(ans,ans^xian[i]);
printf("%lld\n",ans);
return 0;
}