题目:BZOJ2115.
题目大意:给定一张
n
n
n个点
m
m
m条边的无向图,求一条
1
1
1到
n
n
n的路径使得边权异或和最大,输出最大边权异或和.
1
≤
n
≤
5
∗
1
0
4
,
1
≤
m
≤
1
0
5
1\leq n\leq 5*10^4,1\leq m\leq 10^5
1≤n≤5∗104,1≤m≤105,边权
≤
1
0
18
\leq 10^{18}
≤1018.
首先要想到一个性质,任何一条路径 ( 1 , n ) (1,n) (1,n)都可以通过另外一条路径 ( 1 , n ) (1,n) (1,n)通过异或上一些环的异或和来得到.
为什么呢?由于一条路径 ( 1 , n ) (1,n) (1,n)与另一条路径 ( 1 , n ) (1,n) (1,n)必然可以通过删除一些路径段再加上一些路径段来获得,而我们要求的是异或和,而异或的逆运算为异或,每一条删除的路径段也必然对应着一条要加入的路径段使得这两条路径段可以合并成一个环,所以这个性质是正确的.
有了这个性质后,我们就可以把所有路径都对应成一条 ( 1 , n ) (1,n) (1,n)的路径和一堆环;又考虑到是最大异或和,线性基的经典运用啊,然后我们就可以把所有环放到一起跑个线性基就好了.
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=50000,M=100000,C=63;
struct side{
int y,next;
LL v;
}e[M*2+9];
int lin[N+9],top;
void ins(int x,int y,LL v){
e[++top].y=y;e[top].v=v;
e[top].next=lin[x];
lin[x]=top;
}
int n,m,cv,b[N+9];
LL v[M*2+9],d[N+9],ans;
void dfs(int k){
b[k]=1;
for (int i=lin[k];i;i=e[i].next)
if (!b[e[i].y]){
d[e[i].y]=d[k]^e[i].v;
dfs(e[i].y);
}else v[++cv]=d[k]^d[e[i].y]^e[i].v;
}
int Gauss(LL *a,int n){
int now=1,r;
for (int i=C;i>=0;--i){
for (r=now;r<=n;++r)
if (a[r]>>i&1) break;
if (r>n) continue;
if (now^r) swap(a[now],a[r]);
for (int k=1;k<=n;++k)
if (k^now&&a[k]>>i&1)
a[k]^=a[now];
++now;
}
return now-1; //没有返回值直接WA掉...
}
Abigail into(){
scanf("%d%d",&n,&m);
int x,y;LL v;
for (int i=1;i<=m;++i){
scanf("%d%d%lld",&x,&y,&v);
ins(x,y,v);ins(y,x,v);
}
}
Abigail work(){
dfs(1);
cv=Gauss(v,cv);
ans=d[n];
for (int i=1;i<=cv;++i)
ans=max(ans,ans^v[i]);
}
Abigail outo(){
printf("%lld\n",ans);
}
int main(){
into();
work();
outo();
return 0;
}