>Link
luogu P4551
ybtoj最长异或路径
>Description
给定一棵 N 个点的带权树,结点下标从 1 到 N。求树上最长的异或路径。
异或路径指的是指两个结点之间唯一路径上的所有边权的异或。
1 ≤ n ≤ 1 0 5 , 0 ≤ w < 2 31 1≤n≤10^5,0≤w<2^{31} 1≤n≤105,0≤w<231
>解题思路
我们可以预处理根节点到第 i i i个节点的路径上的异或和 a i a_i ai
那根据异或的性质, u u u到 v v v的异或路径就为 a u ⊕ a v a_u⊕a_v au⊕av
那这道题就跟最大异或对一样了
注意:因为 0 ≤ w < 2 31 0≤w<2^{31} 0≤w<231,所以我们就默认每个 a i a_i ai长度为31来处理,不然暴力找最长的 a i a_i ai长度然后再处理的话很容易出一些错误
(主要是懒得调QwQ
>代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 100010
using namespace std;
struct edge
{
int to, nxt, w;
} e[N * 2];
int n, cnt, h[N], a[N], t[N * 30][5], tot;
int sum, ans;
void add (int u, int v, int w)
{
e[++cnt] = (edge){
v, h[u], w}; h[u] = cnt;
e[++cnt] = (edge){
u, h[v], w}; h[v] = cnt;
}
void dfs (int now, int fath)
{
for (int i = h[now]; i; i = e[i].nxt)
{
int v = e[i].to;
if (v == fath) continue;
a[v] = a[now] ^ e[i].w;
dfs (v, now);
}
}
int main()
{
int u, v, w;
scanf ("%d", &n);
for (int i = 1; i < n; i++)
{
scanf ("%d%d%d", &u, &v, &w);
add (u, v, w);
}
dfs (1, 0);
int k, now, x;
for (int i = 1; i <= n; i++)
{
now = 0;
for (int j = 1; j <= 31; j++)
{
x = (a[i] >> (31 - j)) & 1;
if (!t[now][x]) t[now][x] = ++tot;
now = t[now][x];
}
}
for (int i = 1; i <= n; i++)
{
now = sum = 0;
k = 1 << (31 - 1);
for (int j = 1; j <= 31; j++)
{
x = (a[i] >> (31 - j)) & 1;
if (t[now][x ^ 1])
{
sum += k;
now = t[now][x ^ 1];
}
else now = t[now][x];
k >>= 1;
}
ans = max (ans, sum);
}
printf ("%d", ans);
return 0;
}