题解:洛谷 P4551 最长异或路径
【题目来源】
【题目描述】
给定一棵 \(n\) 个点的带权树,结点下标从 \(1\) 开始到 \(n\)。寻找树中找两个结点,求最长的异或路径。
异或路径指的是指两个结点之间唯一路径上的所有边权的异或。
【输入】
第一行一个整数 \(n\),表示点数。
接下来 \(n−1\) 行,给出 \(u,v,w\),分别表示树上的 \(u\) 点和 \(v\) 点有连边,边的权值是 \(w\)。
【输出】
一行,一个整数表示答案。
【输入样例】
4
1 2 3
2 3 4
2 4 6
【输出样例】
7
【解题思路】

【算法标签】
《洛谷 P4551 最长异或路径》 #数学# #贪心# #字典树,Trie#
【代码详解】
#include <bits/stdc++.h>
using namespace std;
// 字典树节点结构体
struct node
{
int left = 0; // 左子节点(存储0)
int right = 0; // 右子节点(存储1)
} root; // 根节点
vector<node> trie; // 字典树存储结构
vector<int> a[100005], b[100005]; // a: 邻接表, b: 边权值
int data[100005]; // 存储每个节点的异或值
int n, x, y, z, ans; // n: 节点数, x/y/z: 临时变量, ans: 最终结果
/**
* 深度优先搜索计算每个节点的异或值
* @param x 当前节点
* @param y 当前异或值
*/
void dfs(int x, int y)
{
for (int i = 0; i < a[x].size(); i++)
{
// 计算子节点的异或值(当前异或值 ^ 边权值)
data[a[x][i]] = y ^ b[x][i];
// 递归处理子节点
dfs(a[x][i], data[a[x][i]]);
}
}
/**
* 构建字典树
* @param x 要插入的数值
*/
void build(int x)
{
int fa = 0; // 从根节点开始
int len; // 新节点位置
// 从最高位到最低位处理
for (int i = (1 << 30); i > 0; i >>= 1)
{
len = trie.size();
if (x & i) // 当前位为1
{
if (trie[fa].right == 0) // 右子节点不存在
{
trie[fa].right = len; // 创建右子节点
trie.push_back(root);
fa = len;
}
else
{
fa = trie[fa].right; // 移动到右子节点
}
}
else // 当前位为0
{
if (trie[fa].left == 0) // 左子节点不存在
{
trie[fa].left = len; // 创建左子节点
trie.push_back(root);
fa = len;
}
else
{
fa = trie[fa].left; // 移动到左子节点
}
}
}
}
/**
* 查询字典树,找到与x异或最大的值
* @param x 要查询的数值
* @return 最大异或值
*/
int query(int x)
{
int ans = 0; // 存储结果
int fa = 0; // 从根节点开始
// 从最高位到最低位处理
for (int i = (1 << 30); i > 0; i >>= 1)
{
int a = x & i; // 获取当前位
if (a) // 当前位为1
{
// 优先选择0(左子节点)以获得更大的异或结果
if (trie[fa].left)
{
ans += i; // 累加结果
fa = trie[fa].left;
}
else
{
fa = trie[fa].right;
}
}
else // 当前位为0
{
// 优先选择1(右子节点)以获得更大的异或结果
if (trie[fa].right)
{
ans += i; // 累加结果
fa = trie[fa].right;
}
else
{
fa = trie[fa].left;
}
}
}
return ans;
}
int main()
{
// 输入节点数
cin >> n;
// 输入树结构(n-1条边)
for (int i = 0; i < n - 1; i++)
{
cin >> x >> y >> z;
a[x].push_back(y); // 构建邻接表
b[x].push_back(z); // 存储边权值
}
// 计算每个节点的异或值(从根节点1开始)
dfs(1, 0);
// 初始化字典树(添加根节点)
trie.push_back(root);
// 将所有节点的异或值插入字典树
for (int i = 1; i <= n; i++)
{
build(data[i]);
}
// 查询每个节点的最大异或值,更新最终结果
for (int i = 1; i <= n; i++)
{
ans = max(ans, query(data[i]));
}
// 输出结果
cout << ans << endl;
return 0;
}
【运行结果】
4
1 2 3
2 3 4
2 4 6
7
浙公网安备 33010602011771号