「WC2011」最大XOR和路径 做题记录
利用了 xor 两次为 \(0\) 的性质。
假设我们已经有了一条路径,要将其拓展至一条新的路径并更新答案,一种可能的拓展是存在一个环与该路径相交,就能将环上路径取反。
再仔细想想,其实不与该路径相交的环也是可以拓展的对象,完全可以从路径上某个点出发,进入该环,绕一圈,沿相同路径回来,
这样做前往环的一部分路径的贡献是重复了的,因此为 \(0\)。
观察这两种拓展,发现每次都可以将原本的路径异或上任意一个环。
相当于确定了一条路径之后,可以选择异或一些环,使异或和最大。可以用线性基搞定。
这条路径如何选择?
任意选即可,如果存在两条不同的路径,它们至少有两个点相交,所以一定存在环可以使两者相拓展。
那么直接把所有环的异或和扔到线性基里,加上任意一条 \(1\) 到 \(n\) 的路径求一下基可表达的最大值即可。
#include<bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fd(i,a,b) for(int i=a;i>=b;--i)
#define ull unsigned long long
using namespace std;
const int N=5e4+10, M=1e5+10;
int n,m,tot,last[N];
bool bz[N];
struct edge{
int st,en,next;ull v;
}E[M<<1];
ull t[100],ans,dis[N];
void add(int x,int y,ull z){
E[++tot]=(edge){x,y,last[x],z};
last[x]=tot;
}
void insert(ull x){
fd(i,62,0)
if(x&(1ll<<i))x^=t[i];
if(x){
fd(i,62,0)
if(x&(1ll<<i)){
t[i]=x;
break;
}
}
}
void dfs(int x,int fr){
bz[x]=1;
for(int p=last[x];p;p=E[p].next){
int y=E[p].en;
if(y==fr)continue;
if(bz[y]){
insert(dis[y]^dis[x]^E[p].v);
}else{
dis[y]=dis[x]^E[p].v;
dfs(y,x);
}
}
}
int main(){
freopen("data.in","r",stdin);
freopen("data.out","w",stdout);
scanf("%d%d",&n,&m);
fo(i,1,m){
int x,y;ull z;
scanf("%d%d%llu",&x,&y,&z);
add(x,y,z);add(y,x,z);
}
dfs(1,0);
ans=dis[n];
fd(i,62,0){
if(!(ans&(1ll<<i)))ans^=t[i];
}
printf("%llu\n",ans);
return 0;
}

浙公网安备 33010602011771号