
由于O(N^2)的存储会超内存限制,所以直接记忆化肯定凉了。
只能考虑O(NlogN)的存储,方法就对每个node都记下,它k=1,2,4,8,…时候的k祖先。比如,可以用f[h][node]表示node的2**h祖先是谁。
需要注意的是,记这个的时候也得做一些优化,直接暴力遍历还是会超时。原理就是:
node的2h2^h2h距离的祖先就是它2h−12^{h-1}2h−1祖先的2h−12^{h-1}2h−1祖先,f[h][node] = f[h-1][f[h-1][node]]。
然后在query的时候,直接跳到最接近的那个位置h,使得2h<=k<2h+12^h<=k<2^{h+1}2h<=k<2h+1,然后找f[h][node]的k−2hk-2^hk−2h祖先即可。
时间复杂度:
- constructor: O(NlogN)O(NlogN)O(NlogN)
- query: O(QlogN)O(QlogN)O(QlogN)
class TreeAncestor:
def __init__(self, n: int, parent: List[int]):
h = floor(log(n, 2))
self.dist = [parent] + [[-1]*n for _ in range(h)] # dist[i][j] = getKthAncestor(j, 2**i)
for i in range(1, h+1):
for j in range(n):
m = self.dist[i-1][j]
if m != -1:
self.dist[i][j] = self.dist[i-1][m]
# print(self.dist)
@lru_cache()
def getKthAncestor(self, node: int, k: int) -> int:
if node == -1:
return -1
h = floor(log(k, 2))
if k > 2**h:
return self.getKthAncestor(self.dist[h][node], k - 2**h)
return self.dist[h][node]
# Your TreeAncestor object will be instantiated and called as such:
# obj = TreeAncestor(n, parent)
# param_1 = obj.getKthAncestor(node,k)
该博客介绍了如何在内存受限的情况下,使用O(NlogN)的存储解决树中节点的祖先查询问题。通过记录每个节点的2的幂次祖先,利用分治策略减少查询时间,实现构造时O(NlogN)和查询时O(QlogN)的时间复杂度。算法通过动态规划优化,避免了暴力遍历导致的超时问题。
1285

被折叠的 条评论
为什么被折叠?



