洛谷P2040题解:巧用异或性质,轻松解决树路径查询
一、问题理解
题目给出一个具有N个节点的树,每条边都有一个权值。然后给出M个查询,每个查询要求计算两个节点之间路径上所有边权的异或值。
二、算法选择
我们可以利用树的以下特性:
树是连通无向无环图
任意两点之间有且只有一条简单路径
异或操作具有自反性:a ^ a = 0
基于这些特性,我们可以使用深度优先搜索(DFS)预处理每个节点到根节点的异或值,然后对于任意查询(u,v),结果就是xor[u] ^ xor[v]。
三、C++代码实现
#include <iostream> #include <vector> using namespace std; const int MAXN = 1e5 + 5; struct Edge { int to, w; }; vector<Edge> tree[MAXN]; int xor_val[MAXN]; // 存储每个节点到根节点的异或值 bool visited[MAXN]; // DFS预处理每个节点到根节点的异或值 void dfs(int u, int current_xor) { visited[u] = true; xor_val[u] = current_xor; for (const Edge& e : tree[u]) { if (!visited[e.to]) { dfs(e.to, current_xor ^ e.w); } } } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int N; cin >> N; // 读取树结构 for (int i = 1; i < N; ++i) { int u, v, w; cin >> u >> v >> w; tree[u].push_back({v, w}); tree[v].push_back({u, w}); } // 预处理异或值 dfs(1, 0); // 假设1是根节点 int M; cin >> M; // 处理查询 while (M--) { int u, v; cin >> u >> v; cout << (xor_val[u] ^ xor_val[v]) << '\n'; } return 0; }
四、代码解析
查询处理:对于查询(u,v),直接输出
xor_val[u] ^ xor_val[v]
即可。
五、学习要点
树的DFS遍历应用
异或运算的特殊性质
预处理思想在算法中的应用
如何将路径查询转化为节点到根节点的查询
六、常见问题解答
Q: 为什么选择DFS而不是BFS?A: 两者都可以,DFS实现更简洁,递归形式更容易理解。
Q: 如果树很大怎么办?A: 算法复杂度已经是线性的,对于更大的树可以考虑更高效的IO方式。
Q: 为什么不用LCA算法?A: 由于异或的特殊性质,我们不需要显式计算LCA,这使得算法更简单高效。
原创内容 转载请注明出处