题目大意:
多组数据,每组数据给出一个有 N N 个节点的树,节点从~ N−1 N − 1 标号,有 N−1 N − 1 条边 ui,vi,wi u i , v i , w i ,表示 xi x i 与 yi y i 有一条连边,边权为 wi w i ,求树中的所有两点间路径的最大 xor x o r 和。
0≤ui,vi<n
0
≤
u
i
,
v
i
<
n
0≤wi<231
0
≤
w
i
<
2
31
1≤N≤100000
1
≤
N
≤
100000
分析:
以
1
1
为根节点跑出一颗树,
设
f[i]
f
[
i
]
表示节点
i
i
到根节点的路径的和,
那么显然,任意两点间路径的
xor
x
o
r
和都是对应的
f[]
f
[
]
互相
xor
x
o
r
的结果
因为他们到根节点的那一段路重复了,根据
x
x
x
x
,所以被抵消了,
那么剩下的
xor
x
o
r
和显然就是他们间路径的
xor
x
o
r
和,
然后我们将
f[]
f
[
]
处理出来以后,
就是求
f
f
数组中,任意个数
xor
x
o
r
的最大
xor
x
o
r
和,
用
trie
t
r
i
e
树解决即可
代码:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define N 100005
using namespace std;
struct Node { int To, nxt, edge; }e[2*N];
int a[32*N][2], val[32*N], ls[N], f[N];
int n, cnt, tot, ans;
void Addedge(int u, int v, int w)
{
e[++cnt].To = v, e[cnt].edge = w, e[cnt].nxt = ls[u], ls[u] = cnt;
e[++cnt].To = u, e[cnt].edge = w, e[cnt].nxt = ls[v], ls[v] = cnt;
}
void dfs(int x, int fa)
{
for (int i = ls[x]; i; i = e[i].nxt)
if (e[i].To != fa)
{
f[e[i].To] = f[x] ^ e[i].edge;
dfs(e[i].To, x);
}
}
void Insert(int x, int y, int num)
{
if(y < 0) {val[x] = num; return;}
int z = (num >> y) & 1;
if (!a[x][z]) a[x][z] = ++tot;
Insert(a[x][z], y - 1, num);
}
int Get_max(int x, int y, int num)
{
if (y < 0) return val[x];
int z = (num >> y) & 1;
if(a[x][z ^ 1]) z ^= 1;
return Get_max(a[x][z], y - 1, num);
}
int main()
{
while (~scanf("%d", &n))
{
ans = 0, cnt = 0, tot = 0;
memset(ls, 0, sizeof(ls));
memset(f, 0, sizeof(f));
memset(a, 0, sizeof(a));
int x, y, z;
for (int i = 1; i < n; i++)
{
scanf("%d %d %d", &x, &y, &z);
Addedge(x + 1, y + 1, z);
}
dfs(1, -1);
Insert(0, 30, 0);
for (int i = 1; i <= n; i++)
{
ans = max(ans, f[i] ^ Get_max(0, 30, f[i]));
Insert(0, 30, f[i]);
}
printf("%d\n", ans);
}
return 0;
}