标签: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\)树中,并在查询时尽可能地往与当前位相反的指针走即可
#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;
}
标签:math ace problem pre lse head tps lang clu
原文地址:https://www.cnblogs.com/xcxc82/p/13907076.html