根据题目要求,对于树中任意两个节点 u 和 v,路径长度为 d(边数),使路径总代价为奇数的赋值方案数为 2^(d-1)。因此核心是快速求树上两点距离。

Python3 实现

```python
class Solution:
    MOD = 10**9 + 7
    
    def assignEdgeWeights(self, edges: List[List[int]], queries: List[List[int]]) -> List[int]:
        n = len(edges) + 1
        
        # 1. 建图(无向树)
        graph = [[] for _ in range(n)]
        for u, v in edges:
            u -= 1
            v -= 1
            graph[u].append(v)
            graph[v].append(u)
        
        # 2. 预处理深度和倍增表
        LOG = (n).bit_length()  # ceil(log2(n)) + 1
        depth = [0] * n
        up = [[0] * LOG for _ in range(n)]
        
        # DFS 构建倍增表
        stack = [(0, -1)]  # (node, parent)
        order = []  # 后序遍历顺序
        parent = [-1] * n
        
        while stack:
            node, par = stack.pop()
            parent[node] = par
            order.append(node)
            for nei in graph[node]:
                if nei != par:
                    depth[nei] = depth[node] + 1
                    stack.append((nei, node))
        
        # 初始化 up[0]
        for i in range(n):
            up[i][0] = parent[i] if parent[i] != -1 else i
        
        # 构建倍增表
        for j in range(1, LOG):
            for i in range(n):
                up[i][j] = up[up[i][j-1]][j-1]
        
        # 3. 预处理 2 的幂次
        pow2 = [1] * (n + 1)
        for i in range(1, n + 1):
            pow2[i] = (pow2[i-1] * 2) % self.MOD
        
        # 4. 处理每个查询
        ans = []
        for u, v in queries:
            u -= 1
            v -= 1
            lca = self._find_lca(u, v, depth, up, LOG)
            dist = depth[u] + depth[v] - 2 * depth[lca]
            ans.append(0 if dist == 0 else pow2[dist - 1])
        
        return ans
    
    def _find_lca(self, u, v, depth, up, LOG):
        """求 LCA"""
        # 确保 u 是较浅的节点
        if depth[u] > depth[v]:
            u, v = v, u
        
        # 将 v 提升到与 u 同深度
        diff = depth[v] - depth[u]
        for j in range(LOG):
            if (diff >> j) & 1:
                v = up[v][j]
        
        if u == v:
            return u
        
        # 同时提升
        for j in range(LOG - 1, -1, -1):
            if up[u][j] != up[v][j]:
                u = up[u][j]
                v = up[v][j]
        
        return up[u][0]
```

优化版本(使用 BFS 替代 DFS)

```python
from collections import deque

class Solution:
    MOD = 10**9 + 7
    
    def assignEdgeWeights(self, edges: List[List[int]], queries: List[List[int]]) -> List[int]:
        n = len(edges) + 1
        
        # 建图
        graph = [[] for _ in range(n)]
        for u, v in edges:
            u, v = u - 1, v - 1
            graph[u].append(v)
            graph[v].append(u)
        
        # BFS 预处理深度和父节点
        LOG = (n).bit_length()
        depth = [0] * n
        up = [[0] * LOG for _ in range(n)]
        
        q = deque([0])
        visited = [False] * n
        visited[0] = True
        parent = [-1] * n
        
        while q:
            node = q.popleft()
            for nei in graph[node]:
                if not visited[nei]:
                    visited[nei] = True
                    depth[nei] = depth[node] + 1
                    parent[nei] = node
                    q.append(nei)
        
        # 初始化倍增表
        for i in range(n):
            up[i][0] = parent[i] if parent[i] != -1 else i
        
        for j in range(1, LOG):
            for i in range(n):
                up[i][j] = up[up[i][j-1]][j-1]
        
        # 预处理 2 的幂
        pow2 = [1] * (n + 1)
        for i in range(1, n + 1):
            pow2[i] = (pow2[i-1] * 2) % self.MOD
        
        # 处理查询
        def lca(u, v):
            if depth[u] > depth[v]:
                u, v = v, u
            
            # 提升 v
            diff = depth[v] - depth[u]
            j = 0
            while diff:
                if diff & 1:
                    v = up[v][j]
                diff >>= 1
                j += 1
            
            if u == v:
                return u
            
            for j in range(LOG - 1, -1, -1):
                if up[u][j] != up[v][j]:
                    u = up[u][j]
                    v = up[v][j]
            
            return up[u][0]
        
        ans = []
        for u, v in queries:
            u, v = u - 1, v - 1
            ancestor = lca(u, v)
            dist = depth[u] + depth[v] - 2 * depth[ancestor]
            ans.append(0 if dist == 0 else pow2[dist - 1])
        
        return ans
```

更简洁的实现(使用递归 DFS)

```python
class Solution:
    MOD = 10**9 + 7
    
    def assignEdgeWeights(self, edges: List[List[int]], queries: List[List[int]]) -> List[int]:
        n = len(edges) + 1
        
        # 建图
        g = [[] for _ in range(n)]
        for u, v in edges:
            u, v = u - 1, v - 1
            g[u].append(v)
            g[v].append(u)
        
        # DFS 预处理
        LOG = n.bit_length()
        depth = [0] * n
        up = [[0] * LOG for _ in range(n)]
        
        def dfs(node, parent):
            up[node][0] = parent if parent != -1 else node
            for j in range(1, LOG):
                up[node][j] = up[up[node][j-1]][j-1]
            for nei in g[node]:
                if nei != parent:
                    depth[nei] = depth[node] + 1
                    dfs(nei, node)
        
        dfs(0, -1)
        
        # LCA 函数
        def get_lca(u, v):
            if depth[u] > depth[v]:
                u, v = v, u
            # 提升 v
            diff = depth[v] - depth[u]
            j = 0
            while diff:
                if diff & 1:
                    v = up[v][j]
                diff >>= 1
                j += 1
            if u == v:
                return u
            for j in range(LOG - 1, -1, -1):
                if up[u][j] != up[v][j]:
                    u = up[u][j]
                    v = up[v][j]
            return up[u][0]
        
        # 预处理 2 的幂
        pow2 = [1] * (n + 1)
        for i in range(1, n + 1):
            pow2[i] = (pow2[i-1] * 2) % self.MOD
        
        # 处理查询
        return [
            0 if dist == 0 else pow2[dist - 1]
            for u, v in queries
            for dist in [depth[u-1] + depth[v-1] - 2 * depth[get_lca(u-1, v-1)]]
        ]
```

复杂度分析

操作 时间复杂度 空间复杂度
预处理 O(n log n) O(n log n)
单次查询 O(log n) O(1)
总体 O((n + q) log n) O(n log n)

其中 n 为节点数,q 为查询数。

核心公式证明

对于路径长度为 d 的路径,每条边可选权重 1 或 2,路径总代价为奇数等价于:

· 路径上有奇数条边权重为 1(其余为 2)
· 从 d 条边中选择奇数条赋值为 1 的方案数

组合数公式:C(d,1) + C(d,3) + C(d,5) + ... = 2^(d-1)

因此答案为 2^(d-1)。当 d = 0 时(即 u = v),方案数为 0。

 

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐