P4551 最长异或路径(01trie模板)

间隙

大致题意

给定一棵(n)个点的带权树,求最长的异或路径。

异或路径指的是指两个结点之间唯一路径上的所有边权的异或

(1≤n≤100000)

分析

01trie模板

(f_i)表示从根节点到(i)节点的异或路径,有显然的递推公式:(f_v = f_{fa}⊕edge.w)

根据异或的性质,(x)(y)之间的异或路径即为(f_v⊕f_u)((a⊕a = 0),即路径上重合的一部分恰好抵消)

于是可以将每个(f_i)的二进制串从左到右插入到一颗(trie)树中,并在查询时尽可能地往与当前位相反的指针走即可

(code)

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 100010;
struct e{
	int u,v,w,next;
}edge[MAXN<<1];
int head[MAXN<<1],cnt = 0;
void add(int u,int v,int w){
	++cnt;
	edge[cnt].w = w;
	edge[cnt].u = u;
	edge[cnt].v = v;
	edge[cnt].next = head[u];
	head[u] = cnt;
}
int n,ans = 0;
int child[MAXN*40][2],tot = 1;
int a[MAXN];
void dfs(int u,int fa){
	for(int i=head[u];i;i=edge[i].next){
		int v = edge[i].v;
		if(v==fa) continue;
		a[v] = a[u]^edge[i].w;
		dfs(v,u);
	}
}
void insert(int a){
	int p = 1;
	for(int i=30;i>=0;i--){
		int now = a>>i&1;
		if(!child[p][now]) child[p][now] = ++tot;
		p = child[p][now];
	}
}
void findmax(int a){
	int res = 0;
	int p = 1;
	for(int i=30;i>=0;i--){
		int now = a>>i&1;
		if(child[p][now^1]){
			res|=1<<i;
			p = child[p][now^1];
		}
		else{
			p = child[p][now];
		}
	}
	ans = max(ans,res);
}
int main(){
	cin>>n;
	for(int i=1;i<=n-1;i++){
		int u,v,w;
		cin>>u>>v>>w;
		add(u,v,w);
		add(v,u,w);
	}
	dfs(1,0);
	for(int i=1;i<=n;i++){
		insert(a[i]);
		findmax(a[i]);
	}
	cout<<ans;
}
原文地址:https://www.cnblogs.com/xcxc82/p/13907076.html