【題解】Acwing228. 異或

Acwing228. 異或

\(\text{Solution:}\)

第一次見的套路 記錄一下

首先觀察到路徑,而且 \(n\) 很大,往最短路方面想,但是一個異或最大值就直接把最短路給幹掉了

考慮什麼東西可以維護形如 選出一些數使得異或和最大 的問題?——線性基。

那麼重新分析題目,我們被要求找到一條路徑滿足異或和最大,而我們不知道如何決策是最優的……

考慮分析一下最優答案的狀態。我們發現,所有可能構成的答案的路徑的並集中,必定有環。因爲它們的起點終點都一樣。

而環又有什麼性質?顯然可以來回走對吧。這就讓我們想起了對應於線性基上選不選的決策。

那麼,環現在是唯一自由的因素了。我們現在被要求選出一些數使得 \(1\) 可以通過它們到達 \(n\) 並且異或和最大化。

而所有路徑都會形成環,也就是說,每條路徑都可以通過 異或上一個環 來轉化爲其他路徑

那這不就和用線性基維護環權值配對了嗎。所以只需要 \(dfs\) 找環加上線性基維護貪心即可。

複雜度 \(O(n\log n)\) 注意代碼裏面直接把線性基消成對角矩陣了。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=4e5+10;
inline int read(){
	int s=0;
	char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();}
	return s;
}
int n,m,head[N],tot;
struct E{int nxt,to,dis;}e[N];
int val[N],vis[N];
struct Line_Base{
	int p[62];
	void insert(int x){
		for(int i=61;~i;--i){
			int v=x>>i&1;
			if(!v)continue;
			if(p[i])x^=p[i];
			else{
				p[i]=x;
				for(int j=i-1;~j;--j)if(p[i]>>j&1)p[i]^=p[j];
				for(int j=61;j>i;--j)if(p[j]>>i&1)p[j]^=p[i];
				return;
			}
		}
	}
	int query(int v){
		for(int i=61;~i;--i)if((v^p[i])>v)v^=p[i];
		return v;
	}
}U;
inline void link(int x,int y,int w){e[++tot]=(E){head[x],y,w};head[x]=tot;}
void dfs(int x){
	vis[x]=1;
	for(int i=head[x];i;i=e[i].nxt){
		int j=e[i].to;
		if(!vis[j]){
			val[j]=val[x]^e[i].dis;
			dfs(j);
		}
		else{
			int v=val[x]^val[j]^e[i].dis;
			if(!v)continue;
			U.insert(v);
		}
	}
}
signed main(){
	freopen("in.txt","r",stdin);
	n=read();m=read();
	for(int i=1;i<=m;++i){
		int x=read(),y=read(),z=read();
		link(x,y,z);link(y,x,z);
	}
	dfs(1);
	printf("%lld\n",U.query(val[n]));
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章