题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2115
解法:
膜:http://www.cnblogs.com/ljh2000-jump/p/5869925.html
这道题要求从1到n的最大xor和路径,存在重边,允许经过重复点、重复边。那么在图上作图尝试之后就会发现,路径一定是由许多的环和一条从1到n的路径组成。容易发现,来回走是没有任何意义的,因为来回走意味着抵消。考虑这道题求得是路径xor和最大,所以必然我们要想办法处理环的情况。我的做法是任意地先找出一条从1到n的路径,把这条路径上的xor和作为ans初值(先不管为什么可行),然后我们的任务就变成了求若干个环与这个ans初值所能组合成的xor最大值。显然,我们需要预处理出图上所有的环,并处理出所有环的环上xor值,这当然是dfs寻找,到n的路径的时候顺便求一下就可以了。
当我们得到了若干个环的xor值之后,因为是要求xor最大值,我们就可以构出这所有xor值的线性基。构出之后,再用ans在线性基上取max就可以了。
为什么可以这么做? 证明在上面大牛博客里有证明。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 50010;
const int maxm = 200010;
int n, m, edgecnt;
int head[maxn];
bool vis[maxn];
LL dx[maxn];
LL p[70];
LL circle[maxm], ans;
void init(){
memset(head, -1, sizeof(head));
edgecnt = 0;
}
struct edge{
int to,next;
LL w;
edge(){}
edge(int to, int next, LL w):to(to),next(next),w(w){}
}E[maxm];
int cnt = 0;
void add(int u, int v, LL w){
E[edgecnt].to = v, E[edgecnt].next = head[u], E[edgecnt].w = w, head[u] = edgecnt++;
}
void dfsloop(int x){
vis[x] = 1;
for(int i=head[x]; i+1; i=E[i].next){
int to = E[i].to;
if(!vis[to]) dx[to] = dx[x]^E[i].w, dfsloop(to);
else{
circle[++cnt] = dx[to]^dx[x]^E[i].w;
}
}
}
int main()
{
int x,y;
LL z;
init();
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);
}
dfsloop(1);
ans = dx[n];//任取一条从1到n的路径,并得到其xor和
for(int i=1; i<=cnt; i++){
for(int j=62; j>=0; j--){
if(!(circle[i]>>j)) continue;
if(!p[j]){
p[j] = circle[i];
break;
}
circle[i] ^= p[j];
}
}
//for(int i=62;i>=0;i--) if(!(ans>>i)) ans^=p[i];
//ans有初值,不能直接根据这一位是否为0来判断是否更大,max更为稳妥
for(int i=62; i>=0; i--){
if((ans^p[i])>ans){
ans = ans^p[i];
}
}
printf("%lld\n", ans);
return 0;
}