leetcode 3559. Number of Ways to Assign Edge Weights II

1. 解题思路

这一题是题目3558. Number of Ways to Assign Edge Weights I的进阶版本。

对于题目3558来说,其核心就是找出树的最大深度,然后就是一个数学题了,要使得这一条路径上的边的总和为奇数,那么其可选的方式为:
N = ∑ i = 1 i ≤ n , i = 1 , 3 , 5 , ⋯ C n i = 2 n − 1 N = \sum\limits_{i=1}^{i \leq n, i=1,3,5,\cdots} C_{n}^{i} = 2^{n-1} N=i=1in,i=1,3,5,Cni=2n1

因此,我们可以直接计算出其结果。

而对于本题,问题增加的难度在于需要快速地任意给到的两个点 u , v u,v u,v,找出这两点间的连接线段的长度,而这个的话事实上和题目3553. Minimum Weighted Subgraph With the Required Paths II非常相近,事实上我们只需要分别求出这两个点 u , v u,v u,v的深度以及他们的最小公共父节点 p p p的深度,那么 u , v u,v u,v间的距离 d d d就可以快速通过下述公式计算得到:
d = h u + h v − 2 × h p d = h_u + h_v - 2\times h_p d=hu+hv2×hp

剩下的就是如何求出 u , v u,v u,v的最小公共父节点了,而这个事实上就是一个经典算法了,这里就不具体展开了,后续有时间的话可能会系统整理一下这个算法然后发一篇博客作为备忘好了。

2. 代码实现

给出python代码实现如下:

MOD = 10**9+7

class LCA:
    def __init__(self, root, tree):
        self.max_level = 20  # 根据树的高度调整
        self.parent = defaultdict(lambda: [-1]*self.max_level)
        self.depth = {}
        self.preprocess(root, tree)

    def preprocess(self, root, tree):
        stack = [(root, -1, 0)]  # (node, parent, depth)
        while stack:
            node, par, d = stack.pop()
            self.depth[node] = d
            self.parent[node][0] = par
            for k in range(1, self.max_level):
                if self.parent[node][k-1] != -1:
                    self.parent[node][k] = self.parent[self.parent[node][k-1]][k-1]
            for child in tree[node]:
                if child != par:
                    stack.append((child, node, d+1))

    def query(self, u, v):
        if self.depth[u] < self.depth[v]:
            u, v = v, u
        # 对齐深度
        for k in range(self.max_level-1, -1, -1):
            if self.depth[u] - (1 << k) >= self.depth[v]:
                u = self.parent[u][k]
        if u == v:
            return u
        # 同步跳转
        for k in range(self.max_level-1, -1, -1):
            if self.parent[u][k] != -1 and self.parent[u][k] != self.parent[v][k]:
                u = self.parent[u][k]
                v = self.parent[v][k]
        return self.parent[u][0]
    
class Solution:
    def assignEdgeWeights(self, edges: List[List[int]], queries: List[List[int]]) -> List[int]:
        graph = defaultdict(list)
        for u, v in edges:
            graph[u].append(v)
            graph[v].append(u)
        
        depth = defaultdict(int)
        tree = defaultdict(list)
        def dfs(u, p):
            nonlocal depth, tree
            if u == 1:
                depth[u] = 0
            else:
                depth[u] = depth[p] + 1
            for v in graph[u]:
                if v == p:
                    continue
                tree[u].append(v)
                dfs(v, u)
            return
        
        dfs(1, 0)
        lca = LCA(1, tree)
        
        def query(u, v):
            p = lca.query(u, v)
            d = depth[u] + depth[v] - 2*depth[p]
            return pow(2, d-1, MOD) if d > 0 else 0
        
        return [query(u, v) for u, v in queries]

提交代码评测得到:耗时2773ms,占用内存137.3MB。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值