资讯动态

树上异或路径算法与实现详解

发布时间:2026/9/8 0:45:43 来源:尧图企业网站定制
1. 题目解析树上异或路径的核心逻辑这道题目的核心在于处理树结构中的路径异或值计算。给定一棵有N个节点的树每条边都有一个权值要求计算所有节点对之间的路径异或值。这里的异或路径指的是两个节点之间唯一路径上所有边权值的异或结果。树结构的特殊性在于任意两个节点之间有且只有一条路径相连这大大简化了问题的复杂度。与图结构不同我们不需要考虑多重路径的情况。在实际游戏开发中这种结构常用于技能树、装备合成路线等场景。2. 算法思路与数学原理2.1 异或运算的特性利用异或运算有几个关键特性可以优化我们的算法自反性a ^ a 0交换律a ^ b b ^ a结合律a ^ (b ^ c) (a ^ b) ^ c恒等性a ^ 0 a这些特性意味着如果我们知道根节点到节点A的异或值x以及根节点到节点B的异或值y那么A到B的路径异或值就是x ^ y。这是因为从根到A再到B的路径中根到最近公共祖先的部分会被异或两次而抵消。2.2 深度优先搜索(DFS)的应用我们可以通过一次DFS遍历预处理所有节点到根节点的异或值从根节点开始DFS维护一个当前异或值初始为0对于每个子节点当前异或值更新为 parent_xor ^ edge_weight递归处理所有子节点这样预处理后任意两点u和v之间的路径异或值就是xor[u] ^ xor[v]。3. Java实现详解import java.util.*; public class TreeXORPaths { static class Edge { int to, weight; Edge(int to, int weight) { this.to to; this.weight weight; } } public static void main(String[] args) { Scanner sc new Scanner(System.in); int n sc.nextInt(); ListEdge[] tree new List[n1]; for (int i 0; i n; i) { tree[i] new ArrayList(); } for (int i 1; i n; i) { int u sc.nextInt(); int v sc.nextInt(); int w sc.nextInt(); tree[u].add(new Edge(v, w)); tree[v].add(new Edge(u, w)); } int[] xor new int[n1]; Arrays.fill(xor, -1); xor[1] 0; QueueInteger q new LinkedList(); q.add(1); while (!q.isEmpty()) { int u q.poll(); for (Edge e : tree[u]) { if (xor[e.to] -1) { xor[e.to] xor[u] ^ e.weight; q.add(e.to); } } } long total 0; for (int i 1; i n; i) { for (int j i1; j n; j) { total xor[i] ^ xor[j]; } } System.out.println(total); } }3.1 Java实现关键点使用邻接表存储树结构每个节点维护一个Edge列表BFS遍历树结构计算每个节点到根节点的异或值双重循环计算所有节点对的异或值之和注意避免重复计算(i,j)和(j,i)提示在实际面试中可以讨论使用位运算优化双重循环的可能性例如按位统计1的个数。4. C实现与性能优化#include iostream #include vector #include queue using namespace std; struct Edge { int to, weight; Edge(int t, int w) : to(t), weight(w) {} }; int main() { int n; cin n; vectorvectorEdge tree(n1); 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); } vectorint xor_val(n1, -1); xor_val[1] 0; queueint q; q.push(1); while (!q.empty()) { int u q.front(); q.pop(); for (const Edge e : tree[u]) { if (xor_val[e.to] -1) { xor_val[e.to] xor_val[u] ^ e.weight; q.push(e.to); } } } long long total 0; for (int bit 0; bit 30; bit) { long long cnt 0; for (int i 1; i n; i) { if (xor_val[i] (1 bit)) cnt; } total cnt * (n - cnt) * (1LL bit); } cout total endl; return 0; }4.1 C优化技巧使用emplace_back避免临时对象构造按位统计优化对于每个bit位统计有多少数的该位是1对于第k位贡献为(1的个数)×(0的个数)×2^k将O(n²)的时间复杂度优化为O(n log max_val)这种优化在n较大时(1e5级别)特别有效是面试中的加分项。5. Python实现与简洁写法import sys from collections import deque def main(): n int(sys.stdin.readline()) tree [[] for _ in range(n1)] for _ in range(n-1): u, v, w map(int, sys.stdin.readline().split()) tree[u].append((v, w)) tree[v].append((u, w)) xor [-1] * (n 1) xor[1] 0 q deque([1]) while q: u q.popleft() for v, w in tree[u]: if xor[v] -1: xor[v] xor[u] ^ w q.append(v) total 0 for bit in range(30): cnt sum(1 for x in xor[1:] if x (1 bit)) total cnt * (n - cnt) * (1 bit) print(total) if __name__ __main__: main()5.1 Python实现特点使用deque实现BFS比列表pop(0)更高效利用生成器表达式统计每位1的个数同样采用按位统计优化避免O(n²)复杂度代码简洁但可读性强适合快速原型开发6. 常见问题与调试技巧6.1 边界条件处理单节点树应该输出0所有边权为0所有路径异或值都是0最大权值情况确保位运算不会溢出6.2 调试技巧打印预处理后的xor数组验证是否正确对小样例(n3)手动计算验证测试链状树和星型树两种极端情况6.3 性能优化思考当n很大时(1e5)O(n²)解法会超时必须使用按位统计可以进一步优化空间不需要存储整个xor数组考虑并行处理不同bit位的统计7. 实际应用场景这类算法在游戏开发中有多种应用技能树解锁条件检查装备合成路径计算游戏地图区域连通性分析成就系统依赖关系验证在米哈游的面试中出现这类题目很可能是考察候选人处理游戏内复杂关系网络的能力。理解如何高效计算树上路径属性对游戏系统开发非常重要。8. 扩展思考如果问题改为求异或值为k的路径数量该如何修改算法如何处理动态更新的边权值在分布式环境下如何实现这类计算这些扩展问题可以帮助深化对算法的理解也是面试中可能出现的follow-up问题。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价