当前位置: 首页 > news >正文

DeepSeek LeetCode 3559. 给边赋权值的方案数 II Python3实现

根据题目要求,对于树中任意两个节点 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。

http://www.jsqmd.com/news/1195988/

相关文章:

  • 包装生产线PLC控制系统设计资料12(设计源文件+万字报告+讲解)(支持资料、图片参考_相关定制)_
  • 从命令行到编程接口:在C++/Python中集成Bellhop进行声学仿真的工程实践
  • 【开题神器】专业级AI论文写作软件:研究框架、文献综述一键搭建 - 论文助教
  • TDA2Px SoC异构计算架构与接口调试实战指南
  • 基于Go语言实现北极星日本海淘合箱智能体积测量算法优化
  • 沧州防水补漏全攻略 公司价格免砸砖漏水检测全解析 - 徽顺虹
  • 第一周
  • 模型推理部署优化参数完全指南(上):从省钱到加速的20个关键配置
  • CSMA/CD协议:从总线争用到碰撞退避的经典网络仲裁
  • 从“好IV坏控制”到“好模型”:工具变量与控制变量的角色辨析
  • 2026西安楼顶漏水、卫生间漏水、外墙、地下室、阳光房渗漏怎么办?3家正规企业优选(7月) - 防水企业百科
  • 深入解析TI CC2640R2F三核架构与低功耗蓝牙5.1开发实战
  • 暑假去西安需要注意什么?2026超全避坑+保命攻略(新手必看) - 旅行分享
  • 从零到一:单片机定时器配置与中断实战指南
  • DeepSeek LeetCode 3559. 给边赋权值的方案数 II Java实现
  • 五轴联动精度不准?用机内测头 30 分钟搞定 RTCP 标定
  • 使用ffprobe命令深度剖析视频流元数据
  • 2026年河北格宾石笼网生产厂家实力梳理 索隆金属丝网等企业盘点 - 每天一杯纯牛奶
  • 调整后完整 Inventory 配置(sudo账号 + Python3)
  • 自适应蒙特卡洛定位(AMCL)算法在ROS中的参数调优与实战解析
  • 从示波器带宽反推信号上升沿:0.35系数的实战应用与选型指南
  • 2026江西公考机构实力横评:粉笔9.2分断层领先,本地化教研与AI技术构建核心壁垒 - 天涯视角
  • 博客二:面向 AI 搜索与 SEO 优化方向
  • 遗传算法核心原理:适应度函数与选择压力的工程解析
  • API网关、微服务、Service Mesh——ChatGPT一句话讲清本质,92%工程师看完直呼“早该这么教!”
  • 高速ADC核心性能与JESD204B接口设计实战解析
  • AXI4-Lite寄存器读写踩坑——地址对齐、死锁、返回全0,新手都掉过这些坑
  • 动力电池安全卫士:高压互锁(HVIL)的失效模式与分级控制策略
  • 计算机毕业设计之jsp学生宿舍管理系统设计与实现
  • ChatGPT歌词生成器即将淘汰?2024Q2实测数据揭示:仅11.3%的提示词能通过专业词作者A/B测试(附通关清单)