「WC2011」最大XOR和路徑 做題記錄
阿新 • • 發佈:2022-04-06
利用了 xor 兩次為 \(0\) 的性質。
假設我們已經有了一條路徑,要將其拓展至一條新的路徑並更新答案,一種可能的拓展是存在一個環與該路徑相交,就能將環上路徑取反。
再仔細想想,其實不與該路徑相交的環也是可以拓展的物件,完全可以從路徑上某個點出發,進入該環,繞一圈,沿相同路徑回來,
這樣做前往環的一部分路徑的貢獻是重複了的,因此為 \(0\)。
觀察這兩種拓展,發現每次都可以將原本的路徑異或上任意一個環。
相當於確定了一條路徑之後,可以選擇異或一些環,使異或和最大。可以用線性基搞定。
這條路徑如何選擇?
任意選即可,如果存在兩條不同的路徑,它們至少有兩個點相交,所以一定存在環可以使兩者相拓展。
那麼直接把所有環的異或和扔到線性基裡,加上任意一條 \(1\)
#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; }