P2420让我们异或吧
代码由人类编写,文章由deepseek官网版本编写
博客食用更佳
题目解析:
本题要求我们在树结构中快速计算两个节点之间路径上所有边的异或值。由于树的结构特性,我们可以利用异或运算的性质来高效解决这个问题。
异或性质的应用:
异或运算具有以下重要性质:
- 自反性:a ^ a = 0
- 交换律和结合律:a ^ b = b ^ a,(a ^ b) ^ c = a ^ (b ^ c)
- 路径抵消性:树中两点间路径的异或值等于它们到根节点异或值的异或。
基于这些性质,我们可以将问题转化为预处理每个节点到根节点的异或值,然后通过简单的异或操作快速得到任意两节点路径的异或值。
解题思路:
-
预处理节点异或值:
- 选择一个根节点(例如节点1),进行深度优先搜索(DFS)或广度优先搜索(BFS)。
- 在遍历过程中,计算每个节点到根节点的异或值。对于当前节点
u
及其子节点v
,边权为w
,则xor[v] = xor[u] ^ w
。
-
处理查询:
- 对于每次查询的两个节点
u
和v
,直接输出xor[u] ^ xor[v]
。根据异或性质,这等价于路径u
到v
上所有边权的异或和。
- 对于每次查询的两个节点
代码实现:
#include <iostream>
#include <vector>
using namespace std;
const int MAXN = 100005;
vector<pair<int, int>> tree[MAXN]; // 邻接表存储树结构
int xorSum[MAXN]; // 存储每个节点到根的异或值
void dfs(int parent, int node, int currentXor) {
xorSum[node] = currentXor;
for (auto &[child, weight] : tree[node]) {
if (child != parent) {
dfs(node, child, currentXor ^ weight);
}
}
}
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].emplace_back(v, w);
tree[v].emplace_back(u, w);
}
// 预处理异或值,根节点设为1
dfs(0, 1, 0);
int m;
cin >> m;
while (m--) {
int u, v;
cin >> u >> v;
cout << (xorSum[u] ^ xorSum[v]) << '\n';
}
return 0;
}
代码解释:
-
数据结构:
- 使用邻接表
tree
存储树结构,每个节点保存其子节点及对应的边权。
- 使用邻接表
-
预处理异或值:
dfs
函数递归遍历树,计算每个节点到根节点的异或值。currentXor
表示当前路径的异或累积值。
-
处理查询:
- 每次查询直接输出两个节点异或值的异或结果,时间复杂度为 O(1)。
复杂度分析:
- 时间复杂度: 预处理 O(n),每次查询 O(1),总复杂度 O(n + m),适用于大规模数据。
- 空间复杂度: O(n),用于存储树结构和异或值数组。
通过巧妙利用异或运算的性质,本方法避免了复杂的路径计算,实现了高效查询,是处理树路径异或问题的经典方法。