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

[WC2011]最大XOR和路徑,洛谷P4151,線性基+Dfs

正題

      這一題挺水的?

      直接隨便求一條1到n的路徑異或和,建出Dfs樹,每一條返祖邊與兩點之間路徑異或和組成環,扔進線性基,最後維護一遍即可。

      首先證明為什麼只用扔返祖環和為什麼可以扔環?

      先解決第二個問題,每一個環肯定可以從1走到其中的某個點上,遍歷一遍這個環,在從開始遍歷的那個點回去。

      那麼1到這個點就被遍歷了兩遍,異或和為0,剩下的環算了一次異或值。

      然後解決第一個問題,因為不是返祖環的環可以有返祖環異或而成。很明顯,自己畫圖即可。

      那麼我們證明了只有環才能帶來價值。

      最後,為什麼隨便選一條路徑?

      因為如果有多條路徑,那麼他們兩兩成環,肯定可以異或出來另一條路徑。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;

int n,m;
struct edge{
	int y,next;
	long long c;
}s[200010];
int first[50010],len=0;
bool tf[50010];
long long dis[50010];
long long p[65];

void ins(int x,int y,long long c){
	len++;
	s[len]=(edge){y,first[x],c};first[x]=len;
}

void insert(long long x){
	for(int i=63;i>=0;i--)
		if(x>>i){
			if(p[i]) x^=p[i];
			else {p[i]=x;break;}
		}
}

void dfs(int x,long long t){
	tf[x]=true;dis[x]=t;
	for(int i=first[x];i!=0;i=s[i].next)
		if(tf[s[i].y]) insert(t^s[i].c^dis[s[i].y]);
		else dfs(s[i].y,dis[x]^s[i].c);
}

int main(){
	scanf("%d %d",&n,&m);
	int x,y;
	long long c;
	for(int i=1;i<=m;i++){
		scanf("%d %d %lld",&x,&y,&c);
		ins(x,y,c);
		ins(y,x,c);
	}
	dfs(1,0);
	long long ans=dis[n];
	for(int i=63;i>=0;i--) ans=max(ans,ans^p[i]);
	printf("%lld",ans);
}