bzoj-2115 Xor
题意:
给出一个有权无向图;
求1到n的路径上的最大异或和。
n<=50000,边权<=10^18。
题解:
因为异或的性质,我们能够知道对于随意一条连通图上的路径的异或和;
都能够由另外一条路径异或若干个环的异或和得来;
由于它们起点和终点都各自是1和n。那么这两个路本身就构成了一个可能经过同样边的环;
而更加显然的是。一个这种非简单环是能够由若干个简单环组成的;
那么异或了这些简单环之后得到了这个非简单环的异或和,再将原来的路径异或上去抵消掉,就是答案了;
所以处理出全部的简单环,和图中随意一条路径的异或和;
然后答案就是任选几个简单环,它们与路径的最大异或和就是答案。
这里用高斯消元来搞就能够了。
时间复杂度 预处理O(n),高斯消元O(60*环的个数);
环不会太多,大概开到了边数就够了;
代码:
#include<vector> #include<stdio.h> #include<string.h> #include<algorithm> #define N 55000 #define M 60 using namespace std; typedef unsigned long long ll; vector<int>to[N]; vector<ll>val[N]; int t[N],tot,n; ll dis[N],a[N<<1],temp; bool vis[N]; void dfs(int x,ll len) { vis[x]=1; if(x==n) temp=len; int i,y; for(i=0;i<to[x].size();i++) { if(!vis[y=to[x][i]]) { dis[y]=len^val[x][i]; dfs(y,dis[y]); } else { if(dis[y]^dis[x]^val[x][i]&&x>y) a[++tot]=dis[y]^dis[x]^val[x][i]; } } } int main() { int m,i,j,k,x,y; ll v,t; scanf("%d%d",&n,&m); for(i=1;i<=m;i++) { scanf("%d%d%llu",&x,&y,&v); to[x].push_back(y),val[x].push_back(v); to[y].push_back(x),val[y].push_back(v); } dfs(1,0); for(i=M,k=0;i>=0;i--) { for(j=k+1,x=0;j<=tot;j++) if((1ll<<i)&a[j]) { x=j; break; } if(!x) continue; else swap(a[++k],a[x]); for(j=1;j<=tot;j++) { if(k==j) continue; if((1ll<<i)&a[j]) a[j]^=a[k]; } } for(i=1;i<=tot;i++) if((temp^a[i])>temp) temp^=a[i]; printf("%llu",temp); return 0; }