先随便找一条1-n的链,异或和为w,然后任选一个节点引到一条环内跑这个环,再回来,由于异或的性质,相当于只是w与换上权值异或。
联想线性基的性质,容易发现:
把所有环的异或和丢到线性基里,用链的值去找最大异或和即可。
这题的难点其实是在找所有环的异或和。
如果这个图是仙人掌就很简单:dfs记录下即可。
但如果这个图是任意无向图。会出现几个换公用一条边,环的数量是n^2级,不可枚举。
但我们只要跑简单环即可。
因为这些公用边的环可以用简单环相互异或得到!
很巧妙的性质!!
CF19E Fairy 同样的性质的一道题,等刷完线性基经典题去看看
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const double PI= acos(-1.0);
const int M = 1e5+7;
int head[M],cnt;
void init(){cnt=0,memset(head,-1,sizeof(head));}
struct EDGE{ll to,nxt,val;}ee[M*2];
void add(int x,int y,ll w){ee[++cnt].nxt=head[x],ee[cnt].to=y,ee[cnt].val=w,head[x]=cnt;}
ll ans,n,m;
ll vs[M],del[M];//del数组记录v之前的异或和, 形成环删去之前的尾巴
ll p[61];
void in(ll x)
{
// cout<<"== -------------- "<<x<<endl;
for(int i=60;i>=0;i--)
{
if(x>>i&1)
{
if(p[i])x^=p[i];
else
{
p[i]=x;
// cout<<"------------"<<i<<" "<<x<<endl;
break;
}
}
}
}
void dfs(int u,int fa,ll w)
{
del[u]=w,vs[u]=1;
for(int i=head[u];i;i=ee[i].nxt)
{
int v=ee[i].to;
if(v==fa)continue;
// cout<<"-- "<<u<<" "<<v<<" "<<w<<" "<<del[v]<<endl;
if(vs[v])in(w^ee[i].val^del[v]);
else dfs(v,u,w^ee[i].val);
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
ll u,v,w;
cin>>n>>m;
for(int i=1;i<=m;i++)cin>>u>>v>>w,add(u,v,w),add(v,u,w);
dfs(1,0,0ll);
// cout<<ans<<endl;
ans=del[n];
for(int i=60;i>=0;i--)
{
// cout<<i<<" "<<p[i]<<" "<<(ans^p[i])<<" "<<ans<<endl;
if((ans^p[i])>ans)ans^=p[i];
}
cout<<ans<<endl;
return 0;
}