码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2020-11-01 10:21:19      阅读:16      评论:0      收藏:0      [点我收藏+]

标签:math   ace   problem   pre   lse   head   tps   lang   clu   

间隙

大致题意

给定一棵\(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;
}

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

标签:math   ace   problem   pre   lse   head   tps   lang   clu   

原文地址:https://www.cnblogs.com/xcxc82/p/13907076.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!