洛谷P4551最长异或路径算法完全解析:从Trie树到DFS的完美结合

问题背景分析
洛谷P4551题目要求在一棵带权树中找出两个节点之间的路径,使得路径上所有边权的异或值最大。这是一个经典的树形结构问题,涉及图论、位运算和数据结构等多个知识点。
核心算法原理
1. 异或路径性质
任意两点u和v的路径异或值等于d[u]^d[v],其中d[i]表示i节点到根的异或值
问题转化为在d数组中找出两个数使它们的异或值最大
2. Trie树优化
算法实现细节
DFS预处理:计算每个节点到根的异或值
Trie树构建:将所有d[i]插入到Trie树中
最大查询:对每个d[i]在Trie树中查询其最大异或对
代码实现
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int MAXN = 1e5 + 5;
const int BIT = 30; // 二进制位数
struct Edge {
int to, w;
};
vector<Edge> G[MAXN];
int trie[MAXN * BIT][2], cnt = 1;
int d[MAXN]; // 存储每个节点到根的异或值
// DFS预处理每个节点到根的异或值
void dfs(int u, int fa) {
for (auto &e : G[u]) {
if (e.to == fa) continue;
d[e.to] = d[u] ^ e.w;
dfs(e.to, u);
}
}
// 插入数字到Trie树
void insert(int x) {
int p = 1; // 根节点
for (int i = BIT; i >= 0; i--) {
int b = (x >> i) & 1;
if (!trie[p][b]) trie[p][b] = ++cnt;
p = trie[p][b];
}
}
// 查询与x异或最大的值
int query(int x) {
int p = 1, res = 0;
for (int i = BIT; i >= 0; i--) {
int b = (x >> i) & 1;
if (trie[p][!b]) {
res += (1 << i);
p = trie[p][!b];
} else {
p = trie[p][b];
}
}
return res;
}
int main() {
int n;
cin >> n;
for (int i = 1; i < n; i++) {
int u, v, w;
cin >> u >> v >> w;
G[u].push_back({v, w});
G[v].push_back({u, w});
}
dfs(1, 0); // 预处理异或路径
int ans = 0;
for (int i = 1; i <= n; i++) {
insert(d[i]);
ans = max(ans, query(d[i]));
}
cout << ans << endl;
return 0;
}代码优化技巧
使用静态数组代替动态分配
预处理避免重复计算
原创内容 转载请注明出处
