結果

問題 No.1600 Many Shortest Path Problems
ユーザー lam6er
提出日時 2025-04-09 20:57:31
言語 PyPy3
(7.3.15)
結果
TLE  
実行時間 -
コード長 6,260 bytes
コンパイル時間 254 ms
コンパイル使用メモリ 82,396 KB
実行使用メモリ 56,488 KB
最終ジャッジ日時 2025-04-09 20:59:31
合計ジャッジ時間 9,276 ms
ジャッジサーバーID
(参考情報)
judge2 / judge4
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample -- * 3
other AC * 4 TLE * 1 -- * 46
権限があれば一括ダウンロードができます

ソースコード

diff #

import sys
from collections import defaultdict, deque
sys.setrecursionlimit(1 << 25)

MOD = 10**9 + 7

def main():
    input = sys.stdin.read().split()
    ptr = 0
    N, M = int(input[ptr]), int(input[ptr+1])
    ptr += 2
    edges = []
    for i in range(M):
        a = int(input[ptr])-1
        b = int(input[ptr+1])-1
        ptr += 2
        edges.append((a, b, i+1))
    parent = list(range(N))
    rank = [1] * N
    mst_edges = []
    non_mst_edges = []
    adj = [[] for _ in range(N)]
    edge_set = set()
    def find(u):
        while parent[u] != u:
            parent[u] = parent[parent[u]]
            u = parent[u]
        return u
    def union(u, v):
        u_root = find(u)
        v_root = find(v)
        if u_root == v_root:
            return False
        if rank[u_root] < rank[v_root]:
            parent[u_root] = v_root
            rank[v_root] += rank[u_root]
        else:
            parent[v_root] = u_root
            rank[u_root] += v_root
        return True
    for idx, (a, b, i) in enumerate(edges):
        if union(a, b):
            mst_edges.append((a, b, i))
            edge_set.add((a, b, i))
            adj[a].append((b, i))
            adj[b].append((a, i))
        else:
            non_mst_edges.append((a, b, i))
    LOG = 20
    up = [[-1] * N for _ in range(LOG)]
    depth = [0] * N
    sum_from_root = [0] * N
    parent_edge = [[] for _ in range(N)]
    q = deque()
    root = 0
    q.append((root, -1))
    while q:
        u, p = q.popleft()
        for v, i in adj[u]:
            if v == p:
                continue
            up[0][v] = u
            depth[v] = depth[u] + 1
            sum_from_root[v] = (sum_from_root[u] + pow(2, i, MOD)) % MOD
            parent_edge[v] = (u, i)
            q.append((v, u))
    up[0][root] = -1
    for k in range(1, LOG):
        for v in range(N):
            if up[k-1][v] == -1:
                up[k][v] = -1
            else:
                up[k][v] = up[k-1][up[k-1][v]]
    def lca(u, v):
        if depth[u] < depth[v]:
            u, v = v, u
        for k in range(LOG-1, -1, -1):
            if depth[u] - (1 << k) >= depth[v]:
                u = up[k][u]
        if u == v:
            return u
        for k in range(LOG-1, -1, -1):
            if up[k][u] != up[k][v]:
                u = up[k][u]
                v = up[k][v]
        return up[0][u]
    def get_path_sum(u, v):
        ancestor = lca(u, v)
        return (sum_from_root[u] + sum_from_root[v] - 2 * sum_from_root[ancestor]) % MOD
    best_bridge = defaultdict(lambda: (float('inf'), None, None))
    for a, b, i in non_mst_edges:
        path = []
        u = a
        v = b
        l = lca(u, v)
        path_edges = set()
        current_u = u
        while current_u != l:
            parent_u = up[0][current_u]
            for p_edge in adj[current_u]:
                if p_edge[0] == parent_u:
                    e = (current_u, parent_u, p_edge[1])
                    break
            path_edges.add(e)
            current_u = parent_u
        current_v = v
        while current_v != l:
            parent_v = up[0][current_v]
            for p_edge in adj[current_v]:
                if p_edge[0] == parent_v:
                    e = (current_v, parent_v, p_edge[1])
                    break
            path_edges.add(e)
            current_v = parent_v
        for edge in path_edges:
            a_edge, b_edge, idx = edge
            if best_bridge[idx][0] > i:
                best_bridge[idx] = (i, a, b)
    Q = int(input[ptr])
    ptr += 1
    for _ in range(Q):
        x = int(input[ptr])-1
        y = int(input[ptr+1])-1
        z = int(input[ptr+2])
        ptr += 3
        if x == y:
            print(0)
            continue
        def find_k(x, y):
            u = x
            v = y
            l = lca(u, v)
            max_edge = 0
            current_u = u
            while current_u != l:
                parent_u = up[0][current_u]
                for p_edge in adj[current_u]:
                    if p_edge[0] == parent_u:
                        max_edge = max(max_edge, p_edge[1])
                        break
                current_u = parent_u
            current_v = v
            while current_v != l:
                parent_v = up[0][current_v]
                for p_edge in adj[current_v]:
                    if p_edge[0] == parent_v:
                        max_edge = max(max_edge, p_edge[1])
                        break
                current_v = parent_v
            return max_edge
        K = find_k(x, y)
        original_sum = get_path_sum(x, y) % MOD
        if z > K:
            print(original_sum)
            continue
        def is_edge_in_path(x, y, z_val):
            edge_found = False
            l = lca(x, y)
            current = x
            while current != l:
                parent_current = up[0][current]
                for p_edge in adj[current]:
                    if p_edge[0] == parent_current:
                        if p_edge[1] == z_val:
                            edge_found = True
                            break
                current = parent_current
                if edge_found:
                    break
            if not edge_found:
                current = y
                while current != l:
                    parent_current = up[0][current]
                    for p_edge in adj[current]:
                        if p_edge[0] == parent_current:
                            if p_edge[1] == z_val:
                                edge_found = True
                                break
                    current = parent_current
                    if edge_found:
                        break
            return edge_found
        if not is_edge_in_path(x, y, z):
            print(original_sum)
            continue
        if z not in best_bridge:
            print(-1)
            continue
        bridge_info = best_bridge.get(z, (float('inf'), None, None))
        if bridge_info[0] == float('inf'):
            print(-1)
            continue
        L, a, b = bridge_info
        new_sum = (pow(2, L, MOD) + get_path_sum(x, a) + get_path_sum(b, y)) % MOD
        print(new_sum if new_sum != 0 else -1)
    return

if __name__ == '__main__':
    main()
0