1. 程式人生 > >洛谷P4151 [WC2011]最大XOR和路徑(線性基)

洛谷P4151 [WC2011]最大XOR和路徑(線性基)

std 回來 int 沒有 moto ext pri 線性 inf

傳送門

首先看到異或就想到線性基

我們考慮有一條路徑,那麽從這條路徑走到圖中的任意一個環再走回這條路徑上,對答案的貢獻是這個環的異或和,走到這個環上的路徑對答案是沒有影響的

以這張(偷來的)圖為例

技術分享圖片

從$1$走到$n$,先走到環再走回來,那麽到環上那條路徑(紅色的)被走了兩次,那麽異或之後為0,對答案無貢獻

那麽我們可以隨意走一條路徑,然後把圖上所有環丟到線性基裏,求一下在這些線性基下最大能異或和是多少,就是個板子了

那麽考慮一下走的路徑會不會對答案有影響

依然考慮(盜來的)

技術分享圖片

一開始走的是$B$這條路徑,但實際上$A$更優,那麽$B$路徑異或上這整個大環的權值就是$A$路徑的權值

找環可以直接dfs

然後沒有然後了

 1 //minamoto
 2 #include<iostream>
 3 #include<cstdio>
 4 #include<cstring>
 5 #define ll long long
 6 using namespace std;
 7 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
 8 char buf[1<<21],*p1=buf,*p2=buf;
9 inline ll read(){ 10 #define num ch-‘0‘ 11 char ch;bool flag=0;ll res; 12 while(!isdigit(ch=getc())) 13 (ch==-)&&(flag=true); 14 for(res=num;isdigit(ch=getc());res=res*10+num); 15 (flag)&&(res=-res); 16 #undef num 17 return res; 18 } 19 ll b[65
]; 20 void insert(ll x){ 21 for(int i=63;i>=0;--i){ 22 if((x>>i)&1){ 23 if(!b[i]){ 24 b[i]=x;return; 25 } 26 x^=b[i]; 27 } 28 } 29 } 30 ll query(ll x){ 31 ll res=x; 32 for(int i=63;i>=0;--i) 33 if((res^b[i])>res) res^=b[i]; 34 return res; 35 } 36 const int N=5e4+5,M=2e5+5; 37 int head[N],Next[M],ver[M],tot;ll edge[M]; 38 inline void add(int u,int v,ll e){ 39 ver[++tot]=v,Next[tot]=head[u],head[u]=tot,edge[tot]=e; 40 } 41 int vis[N];ll del[N]; 42 void dfs(int u,ll res){ 43 del[u]=res,vis[u]=1; 44 for(int i=head[u];i;i=Next[i]) 45 if(!vis[ver[i]]) dfs(ver[i],res^edge[i]); 46 else insert(res^edge[i]^del[ver[i]]); 47 } 48 int main(){ 49 // freopen("testdata.in","r",stdin); 50 int n,m,u,v;ll e;n=read(),m=read(); 51 for(int i=1;i<=m;++i) 52 u=read(),v=read(),e=read(),add(u,v,e),add(v,u,e); 53 dfs(1,0); 54 printf("%lld\n",query(del[n])); 55 return 0; 56 }

洛谷P4151 [WC2011]最大XOR和路徑(線性基)