BZOJ 2115: [Wc2011] Xor
解题思路
因为异或一个数两次相当于这个数不变,思考可能经过的路径,分为两部分,一部分是简单路径,就是直接到n的路径,还有就是环,如果这个环与简单路径间接相连,我们可以直接把环的贡献异或,因为可以先到环转一圈回去,中间的路径经过两次相当于没经过。考虑到状态比较多,我们考虑线性基,dfs找到环与路径,遇到环插入线性基,最后贪心找最大。
代码
#include<iostream>
#include<cstdio>
#define LL long long
using namespace std;
const int MAXN = 50005;
inline LL rd(){
LL x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {x=(x<<1)+(x<<3)+ch-48;ch=getchar();}
return x*f;
}
struct Edge{
LL nxt,to;
LL w;
}edge[MAXN<<2];
LL n,m;
int head[MAXN],cnt;
LL ans,b[70],dis[MAXN];
bool vis[MAXN];
inline void add(LL bg,LL ed,LL v){
edge[++cnt].to=ed;
edge[cnt].w=v;
edge[cnt].nxt=head[bg];
head[bg]=cnt;
}
inline void insert(LL x){
for(register int i=63;~i;i--)
if(x&(1ll<<i)){
if(!b[i]) {b[i]=x;break;}
else x^=b[i];
}
}
inline void dfs(int x){
vis[x]=1;
for(register LL i=head[x];i;i=edge[i].nxt){
LL u=edge[i].to;
if(vis[u]) insert(dis[x]^dis[u]^edge[i].w);
else dis[u]=dis[x]^edge[i].w,dfs(u);
}
}
int main(){
n=rd();m=rd();
for(register LL i=1;i<=m;i++){
LL x,y,z;
x=rd();y=rd();z=rd();
add(x,y,z);add(y,x,z);
}
dfs(1);
ans=dis[n];
// cout<<ans<<endl;
for(register int i=63;i>=0;i--)
if((ans^b[i])>ans) ans^=b[i];
printf("%lld",ans);
}