bzoj2115: [Wc2011] Xor
玄学,位运算。
首先1到n的路径可以看作一条简单路径和套很多环。由于异或的特性直接走和绕环一次再走是有区别的。
预处理出所有的环。
然后用一种类似于gauss消元的方式使每一位尽量为1(就是每个数都只有一位为1,剩下为0)。
然后和res异或就可以了。
#include<cstdio> #include<algorithm> #include<cstring> #define LL long long using namespace std; const int maxn = 50000 + 10; const int maxm = 200000 + 10; LL c[maxm],s[maxm],XOR[maxn],tmp,res; int g[maxn],v[maxm],next[maxm],eid; bool vis[maxn]; int n,m,sp; void addedge(int a,int b,LL C) { v[eid]=b; c[eid]=C; next[eid]=g[a]; g[a]=eid++; v[eid]=a; c[eid]=C; next[eid]=g[b]; g[b]=eid++; } void dfs(int u) { vis[u]=1; for(int i=g[u];~i;i=next[i]) { if(vis[v[i]]) s[++sp]=(XOR[u]^c[i]^XOR[v[i]]); else { XOR[v[i]]=XOR[u]^c[i]; dfs(v[i]); } } } void gauss() { int i,k=0; for(LL j=1ll<<62;j;j>>=1) { for(i=k+1;i<=sp;i++) if(s[i]&j) break; if(i==sp+1) continue; swap(s[++k],s[i]); for(int i=1;i<=sp;i++) if((s[i]&j)&&i!=k) s[i]^=s[k]; } } int main() { memset(g,-1,sizeof(g)); scanf("%d%d",&n,&m); for(int i=1,a,b;i<=m;i++) { scanf("%d%d%lld",&a,&b,&tmp); addedge(a,b,tmp); } dfs(1); gauss(); res=XOR[n]; for(int i=1;s[i];i++) if((res^s[i])>res) res^=s[i]; printf("%lld\n",res); return 0; }