题目链接:
题意:
给定一棵n个点的带权树,结点下标从1开始到N。寻找树中找两个结点,求最长的异或路径。异或路径指的是指两个结点之间唯一路径上的所有边权的异或。
思路:
xor有一个性质:一个值xor 2次相当于没有xor。因此,任意两个节点i,j之间路径的xor值等于1->i的路径xor值异或上1->j的路径xor值(设根节点为1)。所以,只需从根节点开始dfs,把1->i的xor路径值插入到01字典树(Trie)中。遍历到一个点时,先计算该点与已遍历到的其他点之间的xor路径最大值,即在Trie中查找xor最大值。
Tips:1->i也是一条合法路径,因此需要先往Trie中插入0值。
Trie:是从一个数二进制高位->低位插入的(即根节点是最高位,叶子节点为最低位),插入的每个数都补齐成二进制31位。
Code:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 1e5 + 10;
const int MAXN = 1e6 + 10;
typedef struct {
int to, w;
}Point;
int n;
vector<Point>tree[MAX];
int trie[MAXN][2];
int cnt = 0;
int ans = 0;
//Trie插入
void Insert(int x)
{
int root = 0;
for (int i = 30; i >= 0; i--) {
int v = (x >> i) & 1;
if (!trie[root][v]) trie[root][v] = ++cnt;
root = trie[root][v];
}
}
//Trie查询xor最大值
int query(int x)
{
int root = 0;
int val = 0;
for (int i = 30; i >= 0; i--) {
int v = (x >> i) & 1;
if (trie[root][v ^ 1]) {
val += (1 << i);
root = trie[root][v ^ 1];
}
else {
root = trie[root][v];
}
}
return val;
}
void dfs(int root, int fa, int sum)
{
ans = max(ans, query(sum));
for (int i = 0; i < tree[root].size(); i++) {
int to = tree[root][i].to;
if (to == fa) continue;
int w = tree[root][i].w^sum;
Insert(w);
dfs(to, root, w);
}
}
int main()
{
scanf("%d", &n);
for (int i = 1; i < n; i++) {
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
tree[u].push_back(Point{ v,w });
tree[v].push_back(Point{ u,w });
}
//tips
Insert(0);
dfs(1, -1, 0);
printf("%d\n", ans);
return 0;
}