1. 程式人生 > 其它 >P4151 [WC2011]最大XOR和路徑 題解

P4151 [WC2011]最大XOR和路徑 題解

題面

首先考慮沒有環的情況,那麼答案肯定就是 \(1\)\(n\) 簡單路徑的邊權異或和。如果出現環,設這個環邊權異或和為 \(c\),從這條 \(1\)\(n\) 簡單路徑到這個環的路徑邊權異或和為 \(k\),那麼答案為 \(dis_n\oplus k\oplus c\oplus k\)

通過上面的分析,可以發現,答案就是 \(dis_n\) 與所有環的異或和這些數能夠異或起來的最大值,這顯然可以使用線性基來快速解決。注意 \(dis_n\) 是任意一條 \(1\)\(n\) 的路徑異或和即可,因為如果還有其他路徑,一定會出現在環的那部分內,貢獻是一樣的。複雜度 \(O(n\log v)\)

點選檢視程式碼
#include<iostream>
#include<cstdio>
typedef long long ll;
inline ll rd(){
	ll res=0;char c=getchar();
	for(;!isdigit(c);c=getchar());
	for(;isdigit(c);c=getchar())res=(res<<1)+(res<<3)+(c-'0');
	return res;
}
const int N=1e5+13,M=62+13;
struct Onbase{
	ll p[M];
	inline void insert(ll x){
		for(int i=62;i>=0;--i){
			if(!(x&(1ll<<i))) continue;
			if(!p[i]){p[i]=x;break;}
			x^=p[i];
		}
	}
}Base;
struct Edge{int v;ll w;int nxt;}e[N<<1];
int n,m,h[N],tot;
ll dis[N];
bool vis[N];
inline void add_edge(int u,int v,ll w){e[++tot]=(Edge){v,w,h[u]};h[u]=tot;}
void dfs(int u,ll x){
	vis[u]=1,dis[u]=x;
	for(int i=h[u];i;i=e[i].nxt){
		int v=e[i].v;ll w=e[i].w;
		if(!vis[v]) dfs(v,x^w);
		else Base.insert(dis[v]^x^w);
	}
}
int main(){
	n=rd(),m=rd();
	for(int i=1;i<=m;++i){
		int u=rd(),v=rd();ll w=rd();
		add_edge(u,v,w),add_edge(v,u,w);
	}
	dfs(1,0);
	ll ans=dis[n];
	for(int i=62;i>=0;--i)
		if((ans^Base.p[i])>ans) ans^=Base.p[i];
	printf("%lld\n",ans);
	return 0;
}