给定边权为非负的无向图,求1到n边权异或和最大的路径(可以重复经过点和边)。
n≤50000,m≤100000,0≤ei≤1018
PoPoQQQ:
http://blog.youkuaiyun.com/popoqqq/article/details/39804075
一条路径的异或和可以化为一条1到n的简单路径和一些简单环的异或和,我们首先DFS求出任意一条1到n的简单路径以及图中所有线性无关的环(线性基)。
度娘:
1.线性基能相互异或得到原集合的所有相互异或得到的值。
2.线性基是满足性质1的最小的集合。
3.线性基没有异或和为0的子集。
用高斯消元求线性基,其结果的特点是最高位单调,且每个数的最高位只出现在这个数上。
(e.g 110,011->101,011)
最后贪心求解即可。
线性基+dfs生成树
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
template<class T>void sc(T &x){
int f=1;x=0;char c;
while(c=getchar(),c<48)if(c=='-')f=-1;
do x=x*10+(c^48);
while(c=getchar(),c>47);
x*=f;
}
template<class T>void nt(T x){
if(!x)return;
nt(x/10);
putchar('0'+x%10);
}
template<class T>void pt(T x){
if(x<0){
putchar('-');
x=-x;
}
if(!x)putchar('0');
else nt(x);
}
//----------------------------
const int maxn=50004;
const int maxm=100005;
int n,m;
int last[maxm],ecnt;
struct Edge{
int to;ll w;int nxt;
}edge[maxm<<1];
void ins(int u,int v,ll w){
edge[++ecnt]=(Edge){v,w,last[u]};
last[u]=ecnt;
}
ll d[maxm<<1];//*
ll key[maxn];
int tot;
bool vis[maxn];
void dfs(int x){
vis[x]=true;
for(int i=last[x];i;i=edge[i].nxt){
int y=edge[i].to;
if(vis[y]){
ll t=key[x]^key[y]^edge[i].w;
if(t)d[++tot]=t;
}
else{
key[y]=key[x]^edge[i].w;
dfs(y);
}
}
}
void gospoly(){
int i,k=0;
for(ll t=1ll<<62;t;t>>=1){
for(i=k+1;i<=tot;i++)
if(d[i]&t)break;
if(i>tot)continue;
swap(d[++k],d[i]);
for(int j=1;j<=tot;j++)
if(j!=k&&(d[j]&t))d[j]^=d[k];
}
}
int main(){
sc(n);sc(m);
ll w;
for(int u,v,i=1;i<=m;i++){
sc(u);sc(v);sc(w);
ins(u,v,w);
ins(v,u,w);
}
dfs(1);
gospoly();
ll ans=key[n];
for(int i=1;d[i];i++)
if((ans^d[i])>ans)ans^=d[i];
printf("%lld\n",ans);
return 0;
}