結果

問題 No.399 動的な領主
ユーザー navel_tosnavel_tos
提出日時 2024-02-12 18:03:15
言語 PyPy3
(7.3.15)
結果
AC  
実行時間 427 ms / 2,000 ms
コード長 3,834 bytes
コンパイル時間 338 ms
コンパイル使用メモリ 81,828 KB
実行使用メモリ 103,176 KB
最終ジャッジ日時 2024-02-12 18:03:22
合計ジャッジ時間 6,225 ms
ジャッジサーバーID
(参考情報)
judge14 / judge15
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 35 ms
53,460 KB
testcase_01 AC 35 ms
53,460 KB
testcase_02 AC 67 ms
55,604 KB
testcase_03 AC 40 ms
55,604 KB
testcase_04 AC 95 ms
76,656 KB
testcase_05 AC 179 ms
79,260 KB
testcase_06 AC 404 ms
99,080 KB
testcase_07 AC 385 ms
99,080 KB
testcase_08 AC 420 ms
99,464 KB
testcase_09 AC 392 ms
99,464 KB
testcase_10 AC 92 ms
76,484 KB
testcase_11 AC 147 ms
78,472 KB
testcase_12 AC 390 ms
101,768 KB
testcase_13 AC 343 ms
101,768 KB
testcase_14 AC 238 ms
98,696 KB
testcase_15 AC 231 ms
98,696 KB
testcase_16 AC 261 ms
103,176 KB
testcase_17 AC 423 ms
99,336 KB
testcase_18 AC 427 ms
99,464 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

#yukicoder 399 動的な領主

#Heavy-Light decomposition  分解するだけ
class HL_decomposition:
    def __init__(self, N, G, root = 0):
        #pos[v] = i, order[i] = v  頂点vのDFS順がi番目
        #leader[i]: 深さdepth[i]の代表のDFS順  parent[i]: ひとつ根側のDFS順
        self._N = N; self._G = G = [[v for v,*_ in S] for S in G] if N > 1 and not isinstance(G[0][0], int) else G; self.pos = pos = [-1] * N; self.order = order = [-1] * N; self.leader = leader = [-1] * N; self.depth = depth = [-1] * N; self.parent = parent = [-1] * N; size = [1] * N; Q = [(root, -1)]
        for now,back in Q:
            for nxt in G[now]:
                if nxt != back: Q.append((nxt, now))
        while Q: now,back = Q.pop(); size[back] += size[now] if back != -1 else 0
        Q.append((root, -1, 0, -1))
        for i in range(N):
            now, back, d, t = Q.pop(); pos[now], order[i], parent[i], depth[i] = i, now, pos[back], d; leader[i] = t = t if t != -1 else i
            if size[now] > 1:
                s, v = 0, now
                for nxt in G[now]:
                    if nxt == back: continue
                    if s < size[nxt]:
                        if s > 0: Q.append((v, now, d + 1, -1))
                        s, v = size[nxt], nxt
                    else: Q.append((nxt, now, d + 1, -1))
                Q.append((v, now, d, t))
    def LCA(self, u, v):
        i, j = self.pos[u], self.pos[v]; c, d = self.depth[i], self.depth[j]; s, t = self.leader[i], self.leader[j]
        for c in range(c - 1, d - 1, -1): i = self.parent[s]; s = self.leader[i]
        for d in range(d - 1, c - 1, -1): j = self.parent[t]; t = self.leader[j]
        while s != t: i, j = self.parent[s], self.parent[t]; s, t = self.leader[i], self.leader[j]
        return self.order[ min(i, j) ]        
    def find(self, index_u, v = None):  #対応する列の添字を返す
        return self.pos[index_u] if v == None else max( self.pos[index_u], self.pos[v] )
    def rev(self, Lt, Rt = None):  #B = A[::-1]  A[i], A[Lt,Rt)の対応添字を返す
        return self._N - 1 - Lt if Rt == None else (self._N - Rt, self._N - Lt)
    def fold(self, u, v):
        #u→vパスの作用値順を(to, go, LCA)の順に返す
        #to, goともに下から区間作用を行い、最後にf( f(to, A[LCA]), go )を行う
        #to: LCA ← uの作用区間[Lt,Rt)  x ← f( x, fold(Lt, Rt) ) の順  反転列を使う  
        #go: LCA → vの作用区間[Lt,Rt)  y ← f( fold(Lt, Rt), y ) の順
        i, j = self.pos[u], self.pos[v]; c, d = self.depth[i], self.depth[j]; s, t = self.leader[i], self.leader[j]; to, go = [], []
        for c in range(c - 1, d - 1, -1): to.append((s, i + 1)); i = self.parent[s]; s = self.leader[i]
        for d in range(d - 1, c - 1, -1): go.append((t, j + 1)); j = self.parent[t]; t = self.leader[j]
        while s != t: to.append((s, i + 1)); i = self.parent[s]; s = self.leader[i]; go.append((t, j + 1)); j = self.parent[t]; t = self.leader[j]
        if i > j: to.append((j + 1, i + 1))
        if i < j: go.append((i + 1, j + 1))
        return to, go, min(i, j)



#入力受取
N = int(input())
G = [[] for _ in range(N)]
for _ in range(N - 1):
    u,v = map(int,input().split())
    G[u - 1].append(v - 1)
    G[v - 1].append(u - 1)

#HLD
HLD = HL_decomposition(N, G)

#累積和配列を定義
A = [0] * (N + 1)

#HLDでクエリを実行
for _ in range(int(input())):
    u,v = map(int,input().split())
    u,v = u-1, v-1

    #パスを取得
    to, go, LCA = HLD.fold(u, v)

    #to, goに区間加算  LCAに一点加算
    for Lt,Rt in to + go:
        A[Lt] += 1
        A[Rt] -= 1
    A[LCA] += 1
    A[LCA + 1] -= 1

#累積和の総和を出力
ans = 0
for i in range(N):
    ans += A[i] * (A[i] + 1) // 2
    A[i + 1] += A[i]
print(ans)
0