题目描述
题解
挺好的一道思路题…
首先一条路径一定可以分解成一条简单路径和若干环的异或值
只需要dfs一遍所有能dfs到的环,剩余的环都可以通过其它的环组合(异或)得到
而简单路径可以是任意一条,因为环不一定和简单路径只有一个公共点(画图…不过据说可以证明?)
所以,dfs出任意一条简单路径,再dfs出所有环(每一个点只访问一遍),问题转化为将若干环组合与简单路径的异或最大
对于环求线性无关组
然后贪心地从高位到低位枚举,对于不是1的某一位贪心地搞成1就行了…
代码
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define LL long long
#define N 1000005
int n,m,x,y,acnt,bcnt,vis[N];
int tot,point[N],nxt[N],v[N];LL c[N];
LL z,h[N],mi[N],a[N],b[N],road,ans;
void add(int x,int y,LL z)
{
++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; c[tot]=z;
}
void dfs(int x)
{
if (x==n) road=h[x];
for (int i=point[x];i;i=nxt[i])
{
if (vis[v[i]])
{
LL t=h[x]^c[i]^h[v[i]];
if (t) a[++acnt]=t;
}
else
{
vis[v[i]]=1;
h[v[i]]=h[x]^c[i];
dfs(v[i]);
}
}
}
int main()
{
mi[0]=1LL;for (int i=1;i<=59;++i) mi[i]=mi[i-1]*2LL;
scanf("%d%d",&n,&m);
for (int i=1;i<=m;++i)
{
scanf("%d%d%lld",&x,&y,&z);
add(x,y,z);add(y,x,z);
}
h[1]=0;vis[1]=1;dfs(1);
memset(vis,0,sizeof(vis));
for (int i=1;i<=acnt;++i)
for (int j=59;j>=0;--j)
if (a[i]&mi[j])
{
if (!vis[j])
{
vis[j]=i;
b[++bcnt]=a[i];
break;
}
else a[i]^=a[vis[j]];
}
sort(b+1,b+bcnt+1);
for (int i=1;i<bcnt;++i)
{
int bit=60;
for (int j=59;j>=0;--j)
if (b[i]&mi[j]) {bit=j;break;}
for (int j=i+1;j<=bcnt;++j)
if (b[j]&mi[bit]) b[j]^=b[i];
}
ans=road;
for (int i=bcnt;i>=1;--i)
{
int bit=60;
for (int j=59;j>=0;--j)
if (b[i]&mi[j]) {bit=j;break;}
if (ans&mi[bit]) continue;
ans^=b[i];
}
printf("%lld\n",ans);
}