結果
問題 | No.1094 木登り / Climbing tree |
ユーザー | kept1994 |
提出日時 | 2022-11-23 14:43:15 |
言語 | PyPy3 (7.3.15) |
結果 |
AC
|
実行時間 | 1,535 ms / 2,000 ms |
コード長 | 3,400 bytes |
コンパイル時間 | 350 ms |
コンパイル使用メモリ | 82,072 KB |
実行使用メモリ | 141,524 KB |
最終ジャッジ日時 | 2024-09-24 19:01:36 |
合計ジャッジ時間 | 37,659 ms |
ジャッジサーバーID (参考情報) |
judge2 / judge4 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 40 ms
54,220 KB |
testcase_01 | AC | 1,535 ms
130,748 KB |
testcase_02 | AC | 295 ms
141,524 KB |
testcase_03 | AC | 582 ms
82,356 KB |
testcase_04 | AC | 536 ms
101,048 KB |
testcase_05 | AC | 665 ms
123,856 KB |
testcase_06 | AC | 957 ms
94,552 KB |
testcase_07 | AC | 1,505 ms
131,280 KB |
testcase_08 | AC | 1,479 ms
132,092 KB |
testcase_09 | AC | 1,455 ms
129,748 KB |
testcase_10 | AC | 1,433 ms
130,444 KB |
testcase_11 | AC | 1,440 ms
131,084 KB |
testcase_12 | AC | 1,473 ms
130,488 KB |
testcase_13 | AC | 1,479 ms
130,316 KB |
testcase_14 | AC | 1,438 ms
130,132 KB |
testcase_15 | AC | 837 ms
91,060 KB |
testcase_16 | AC | 1,043 ms
126,768 KB |
testcase_17 | AC | 935 ms
106,200 KB |
testcase_18 | AC | 902 ms
98,548 KB |
testcase_19 | AC | 1,001 ms
118,236 KB |
testcase_20 | AC | 1,463 ms
129,916 KB |
testcase_21 | AC | 949 ms
108,548 KB |
testcase_22 | AC | 1,450 ms
130,376 KB |
testcase_23 | AC | 1,485 ms
131,152 KB |
testcase_24 | AC | 1,421 ms
129,696 KB |
testcase_25 | AC | 1,455 ms
130,752 KB |
testcase_26 | AC | 1,484 ms
131,384 KB |
ソースコード
#!/usr/bin/env python3 import sys class LcaDoubling: # 木であれば任意の点を根と見做せる。 def __init__(self, N, root=0): self.N = N self.root = root self.G = [[] for _ in range(N)] self.depths = [-1] * N self.distances = [-1] * N self.ancestors = [] return def addEdge(self, fromNode: int, toNode: int, cost: int): self.G[fromNode].append((cost, toNode)) # print("Really directed Graph?") return def build(self): prevAncestors = self._dfs() self.ancestors.append(prevAncestors) d = 1 max_depth = max(self.depths) while d < max_depth: nextAncestors = [prevAncestors[p] for p in prevAncestors] self.ancestors.append(nextAncestors) d <<= 1 prevAncestors = nextAncestors return def _dfs(self): q = [(self.root, -1, 0, 0)] directAncestors = [-1] * (self.N + 1) # 頂点数より1個長くし、存在しないことを-1で表す。末尾(-1)要素は常に-1 while q: now, parent, dep, dist = q.pop() directAncestors[now] = parent self.depths[now] = dep self.distances[now] = dist for cost, next in self.G[now]: if next != parent: q.append((next, now, dep + 1, dist + cost)) return directAncestors def getLca(self, nodeA: int, nodeB: int): depthA, depthB = self.depths[nodeA], self.depths[nodeB] if depthA > depthB: nodeA, nodeB = nodeB, nodeA depthA, depthB = depthB, depthA # 2ノードを同じ深さまで揃える。 tu = nodeA tv = self.upstream(nodeB, depthB - depthA) # 遡上させて行き2つが衝突する位置が共通祖先。 if nodeA == tv: return nodeA for k in range(depthA.bit_length() - 1, -1, -1): mu = self.ancestors[k][tu] mv = self.ancestors[k][tv] if mu != mv: tu = mu tv = mv lca = self.ancestors[0][tu] assert lca == self.ancestors[0][tv] return lca # 2つのノードの間の距離を返す。 def getDistance(self, nodeA, nodeB): lca = self.getLca(nodeA, nodeB) return self.distances[nodeA] + self.distances[nodeB] - 2 * self.distances[lca] # targetNodeが2つのノード間のパス上に存在するかを返す。 def isOnPath(self, nodeA: int, nodeB: int, evalNode: int): return self.getDistance(nodeA, nodeB) == self.getDistance(nodeA, evalNode) + self.getDistance(evalNode, nodeB) # ノードvからk個遡上したノードを返す。 def upstream(self, v, k): i = 0 while k: if k & 1: v = self.ancestors[i][v] k >>= 1 i += 1 return v def main(): N = int(input()) ld = LcaDoubling(N) for _ in range(N - 1): a, b, c = map(int, input().split()) ld.addEdge(fromNode=a - 1, toNode=b - 1, cost=c) ld.addEdge(fromNode=b - 1, toNode=a - 1, cost=c) ld.build() Q = int(input()) for _ in range(Q): s, t = map(int, input().split()) print(ld.getDistance(nodeA=s - 1, nodeB=t - 1)) if __name__ == '__main__': main()