当前位置:首页 > 洛谷题解 > 洛谷P2040题解:巧用异或性质,轻松解决树路径查询

洛谷P2040题解:巧用异或性质,轻松解决树路径查询

4天前洛谷题解66

截图未命名.jpg 洛谷P2040题解:巧用异或性质,轻松解决树路径查询 树结构 异或运算 DFS算法 洛谷题解 C++ 第1张

一、问题理解

题目给出一个具有N个节点的树,每条边都有一个权值。然后给出M个查询,每个查询要求计算两个节点之间路径上所有边权的异或值。

二、算法选择

我们可以利用树的以下特性:

  1. 树是连通无向无环图

  2. 任意两点之间有且只有一条简单路径

  3. 异或操作具有自反性: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;
}

四、代码解析

  1. 数据结构:使用邻接表tree存储树结构,每个节点保存其相邻节点及边权。

  2. 预处理DFS遍历树,计算每个节点到根节点的异或值,存储在xor_val数组中。

  3. 查询处理:对于查询(u,v),直接输出xor_val[u] ^ xor_val[v]即可。

五、学习要点

  1. 树的DFS遍历应用

  2. 异或运算的特殊性质

  3. 预处理思想在算法中的应用

  4. 如何将路径查询转化为节点到根节点的查询

六、常见问题解答

Q: 为什么选择DFS而不是BFSA: 两者都可以,DFS实现更简洁,递归形式更容易理解。

Q: 如果树很大怎么办?A: 算法复杂度已经是线性的,对于更大的树可以考虑更高效的IO方式。

Q: 为什么不用LCA算法A: 由于异或的特殊性质,我们不需要显式计算LCA,这使得算法更简单高效。


原创内容 转载请注明出处

分享给朋友:

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。