144. 最长异或值路径

 

给定一个树,树上的边都具有权值。

树中一条路径的异或长度被定义为路径上所有边的权值的异或和:

Acwing - 144 最长异或值路径_ci

⊕ 为异或符号。

给定上述的具有n个节点的树,你能找到异或长度最大的路径吗?

输入格式

第一行包含整数n,表示树的节点数目。

接下来n-1行,每行包括三个整数u,v,w,表示节点u和节点v之间有一条边权重为w。

输出格式

输出一个整数,表示异或长度最大的路径的最大异或和。

数据范围

1≤n≤1000001≤n≤100000,
0≤u,v<n0≤u,v<n,
0≤w<2310≤w<231

输入样例:

4
0 1 3
1 2 4
1 3 6

输出样例:

7

样例解释

样例中最长异或值路径应为0->1->2,值为7 (=3 ⊕ 4)

题解 :  设 D[x] 表示根节点到 x 的路径上所有边权的 xor 值 , 显然有:  

                             D[x] = D[father(x) ] xor weight(x,father(x)) 

   根据上式, 我们可以对树dfs一遍 ,求出所有的 D[x] , 不难发现,树上 x 到 y 的路径上的所有边权的 xor 结果 就等于 D[x] xor D[y].

 这是根据 异或的性质( a xor a = 0 ) ,  "x到根 "  和" y 到根 " 这两条路径重叠的部分恰好抵消。 , 

 问题就转化成 了从  D[1] ~D[n] 这 n 个数中选出两个数, 使得xor 结果最大。

 

  

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
const int MAX = 100015 ;
typedef long long LL ;
int n ;
int D[MAX] ;
int trie[MAX*32][2] ;

struct Edge {
int next ;
int to ;
int w ;
};
int cnt ;
int tot = 1 ;
int vis[MAX*2];
Edge edge[MAX*2] ;
int head[MAX*2] ;
void add(int u ,int v ,int w){
edge[++cnt].next = head[u] ;
edge[cnt].to = v ;
edge[cnt].w = w ;
head[u] = cnt ;
return ;
}
void dfs(int v ){
vis[v] = 1 ;
for(int i = head[v] ; i ; i = edge[i].next) {
if(!vis[edge[i].to]){
D[edge[i].to] = D[v]^edge[i].w ;
dfs(edge[i].to) ;
}
}
return ;
}
void insert(int x ){
int p = 1 ;
for(int k = 30 ; k >=0 ; k-- ){
int ch = (x>>k)&1 ; // 取出第 k 位
if(!trie[p][ch]){
trie[p][ch] = ++ tot ;
}
p = trie[p][ch] ;
}
return ;
}
int query(int x){
int p = 1 ;
int ans = 0 ;
for(int k = 30 ; k>=0 ; k--){
int ch = (x>>k)&1 ;
if(trie[p][ch^1]){
p = trie[p][ch^1] ;
ans|=(1<<k) ;
}
else{
p = trie[p][ch] ;
}
}
return ans ;
}
int main(){
cin >>n ;
for(int i = 1 ; i<n ; i++ ) {
int u ,v ,w ;
cin >> u >>v >>w ;
add(u,v,w) ;
add(v,u,w) ;
}
dfs(0) ;
int res = 0 ;
for(int i = 0 ; i<n ; i++ ){
insert(D[i]) ;

res = max(res,query(D[i])) ;
}

cout<<res ;
return 0 ;
}