結果

問題 No.1600 Many Shortest Path Problems
ユーザー chineristACchineristAC
提出日時 2021-07-10 02:19:38
言語 PyPy3
(7.3.15)
結果
TLE  
実行時間 -
コード長 7,103 bytes
コンパイル時間 155 ms
コンパイル使用メモリ 82,380 KB
実行使用メモリ 463,980 KB
最終ジャッジ日時 2024-07-01 21:21:19
合計ジャッジ時間 83,875 ms
ジャッジサーバーID
(参考情報)
judge4 / judge1
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 51 ms
57,984 KB
testcase_01 AC 55 ms
58,240 KB
testcase_02 AC 49 ms
57,984 KB
testcase_03 AC 49 ms
57,856 KB
testcase_04 TLE -
testcase_05 TLE -
testcase_06 AC 49 ms
57,600 KB
testcase_07 AC 51 ms
57,856 KB
testcase_08 AC 50 ms
57,856 KB
testcase_09 AC 50 ms
57,984 KB
testcase_10 AC 936 ms
236,044 KB
testcase_11 AC 1,409 ms
249,904 KB
testcase_12 AC 2,546 ms
299,896 KB
testcase_13 AC 3,755 ms
393,308 KB
testcase_14 TLE -
testcase_15 AC 50 ms
57,856 KB
testcase_16 AC 50 ms
58,112 KB
testcase_17 AC 3,338 ms
354,612 KB
testcase_18 TLE -
testcase_19 AC 50 ms
57,728 KB
testcase_20 AC 51 ms
58,496 KB
testcase_21 AC 3,270 ms
353,760 KB
testcase_22 AC 50 ms
57,984 KB
testcase_23 AC 49 ms
57,856 KB
testcase_24 TLE -
testcase_25 AC 50 ms
58,240 KB
testcase_26 AC 49 ms
57,984 KB
testcase_27 AC 50 ms
58,496 KB
testcase_28 AC 50 ms
58,112 KB
testcase_29 AC 2,320 ms
353,872 KB
testcase_30 AC 2,500 ms
353,212 KB
testcase_31 AC 2,477 ms
351,908 KB
testcase_32 AC 2,519 ms
352,236 KB
testcase_33 AC 50 ms
57,728 KB
testcase_34 AC 50 ms
58,112 KB
testcase_35 AC 3,029 ms
462,224 KB
testcase_36 AC 2,624 ms
455,352 KB
testcase_37 AC 51 ms
58,240 KB
testcase_38 AC 1,847 ms
349,680 KB
testcase_39 AC 51 ms
58,496 KB
testcase_40 AC 2,752 ms
353,948 KB
testcase_41 AC 1,921 ms
343,000 KB
testcase_42 AC 2,042 ms
343,644 KB
testcase_43 AC 2,192 ms
344,932 KB
testcase_44 AC 2,460 ms
348,456 KB
testcase_45 AC 2,330 ms
354,844 KB
testcase_46 AC 2,314 ms
352,500 KB
testcase_47 AC 3,235 ms
360,744 KB
testcase_48 AC 3,262 ms
355,736 KB
testcase_49 AC 53 ms
57,856 KB
testcase_50 AC 50 ms
57,728 KB
testcase_51 AC 49 ms
57,984 KB
testcase_52 AC 49 ms
57,472 KB
testcase_53 AC 49 ms
57,600 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

class UnionFindVerSize():
    def __init__(self, N):
        self._parent = [n for n in range(0, N)]
        self._size = [1] * N
        self.group = N

    def find_root(self, x):
        if self._parent[x] == x: return x
        self._parent[x] = self.find_root(self._parent[x])
        stack = [x]
        while self._parent[stack[-1]]!=stack[-1]:
            stack.append(self._parent[stack[-1]])
        for v in stack:
            self._parent[v] = stack[-1]
        return self._parent[x]

    def unite(self, x, y):
        gx = self.find_root(x)
        gy = self.find_root(y)
        if gx == gy: return

        self.group -= 1

        if self._size[gx] < self._size[gy]:
            self._parent[gx] = gy
            self._size[gy] += self._size[gx]
        else:
            self._parent[gy] = gx
            self._size[gx] += self._size[gy]

    def get_size(self, x):
        return self._size[self.find_root(x)]

    def is_same_group(self, x, y):
        return self.find_root(x) == self.find_root(y)

class SegmentTree:
    def __init__(self, init_val, segfunc, ide_ele):
        n = len(init_val)
        self.segfunc = segfunc
        self.ide_ele = ide_ele
        self.num = 1 << (n - 1).bit_length()
        self.tree = [ide_ele] * 2 * self.num
        self.size = n
        for i in range(n):
            self.tree[self.num + i] = init_val[i]
        for i in range(self.num - 1, 0, -1):
            self.tree[i] = self.segfunc(self.tree[2 * i], self.tree[2 * i + 1])

    def update(self, k, x):
        k += self.num
        self.tree[k] = x
        while k > 1:
            k >>= 1
            self.tree[k] = self.segfunc(self.tree[2*k],self.tree[2*k+1])

    def query(self, l, r):
        if r==self.size:
            r = self.num

        res = self.ide_ele

        l += self.num
        r += self.num
        right = []
        while l < r:
            if l & 1:
                res = self.segfunc(res, self.tree[l])
                l += 1
            if r & 1:
                right.append(self.tree[r-1])
            l >>= 1
            r >>= 1

        for y in right[::-1]:
            res = self.segfunc(res,y)
        return res

class SparseTable():
    def __init__(self,A,merge_func,ide_ele):
        N = len(A)
        n = N.bit_length()
        self.N = N
        self.n = n
        self.table=[[ide_ele for i in range(n)] for i in range(N)]
        self.merge_func=merge_func

        for i in range(N):
            self.table[i][0]=A[i]

        for j in range(1,n):
            for i in range(0,N-2**j+1):
                f=self.table[i][j-1]
                s=self.table[i+2**(j-1)][j-1]
                self.table[i][j]=self.merge_func(f,s)

    def query(self,s,t):
        b=t-s+1
        m=b.bit_length()-1
        return self.merge_func(self.table[s][m],self.table[t-2**m+1][m])

import sys,random,bisect
from collections import deque,defaultdict
from heapq import heapify,heappop,heappush
from itertools import permutations
from math import gcd,log

input = lambda :sys.stdin.buffer.readline()
mi = lambda :map(int,input().split())
li = lambda :list(mi())

mod = 10**9 + 7

N,M = mi()
uf = UnionFindVerSize(N)
E = []
edge = [[] for v in range(N)]
gomi = []
cost = 2
for i in range(M):
    u,v = mi()
    u,v = u-1,v-1
    E.append((u,v,i,cost))
    if not uf.is_same_group(u,v):
        uf.unite(u,v)
        edge[u].append((v,i,cost))
        edge[v].append((u,i,cost))
    else:
        gomi.append((u,v,i,cost))
    cost = 2 * cost % mod
parent = [0 for v in range(N)]
depth = [0 for v in range(N)]
rank = [0 for v in range(N)]
v_to_e = [-1 for i in range(N)]
deq = deque([0])
while deq:
    v = deq.popleft()
    for nv,idx,c in edge[v]:
        if nv==parent[v]:
            continue
        parent[nv] = v
        depth[nv] = (depth[v] + c) % mod
        rank[nv] = rank[v] + 1
        v_to_e[nv] = idx
        deq.append(nv)

begin = [0 for v in range(N)]
end = [0 for v in range(N)]
cnt = [0 for v in range(N)]
stack = [0]
euler_tour = []
while stack:
    v = stack[-1]
    euler_tour.append(v)
    if cnt[v] == len(edge[v]):
        end[v] = len(euler_tour) - 1
        stack.pop()
    else:
        nv,idx,c = edge[v][cnt[v]]
        cnt[v] += 1
        if nv==parent[v]:
            continue

        begin[nv] = len(euler_tour)
        stack.append(nv)

init = [(rank[v]<<20)+v for v in euler_tour]
seg_lca = SparseTable(init,min,10**17)
mask = 2**20-1

def lca(u,v):
    l = min(begin[u],begin[v])
    r = max(end[u],end[v])
    r = seg_lca.query(l,r)
    p = r & mask
    return p

def dist(x,y):
    p = lca(x,y)
    return (depth[x] + depth[y] - 2 * depth[p]) % mod

Q = int(input())
LCA = [-1 for v in range(Q)]
query = []
for _ in range(Q):
    x,y,z = mi()
    LCA[_] = lca(x-1,y-1)
    query.append((x-1,y-1,z-1))

check_time = [[] for v in range(N)]
for i in range(Q):
    x,y,z = query[i]
    p = LCA[i]
    check_time[x].append((i,p,z))
    check_time[y].append((i,p,z))

alt = [[] for v in range(N)]
for u,v,idx,c in gomi[::-1]:
    p = lca(u,v)

    while alt[u]:
        pre_idx,pre_p = alt[u][-1]
        if rank[pre_p] >= rank[p]:
            alt[u].pop()
        else:
            break
    alt[u].append((idx,p))

    while alt[v]:
        pre_idx,pre_p = alt[v][-1]
        if rank[pre_p] >= rank[p]:
            alt[v].pop()
        else:
            break
    alt[v].append((idx,p))

delete_query = [[] for v in range(N)]
for v in range(N):
    for idx,p in alt[v]:
        delete_query[p].append(v)


z_on_path = [-1 for i in range(Q)]
alt_edge = [-1 for v in range(M)]
seg = SegmentTree([M]*len(euler_tour),min,M)
edge_on_path = []
appear = [-1 for i in range(M)]
for i in range(1,len(euler_tour)):
    v = euler_tour[i]
    if i==end[v]:
        if v!=0:
            appear[edge_on_path.pop()] = -1

            for cv in delete_query[v]:
                alt[cv].pop()
                if alt[cv]:
                    seg.update(begin[cv],alt[cv][-1][0])
                else:
                    seg.update(begin[cv],M)

            e = v_to_e[v]
            res = seg.query(begin[v],end[v])
            if res!=M:
                alt_edge[e] = res
    elif i==begin[v]:
        #assert i==begin[v]
        idx = v_to_e[v]
        appear[idx] = len(edge_on_path)
        edge_on_path.append(idx)
        for i,p,z in check_time[v]:
            if rank[p] <= appear[z]:
                z_on_path[i] = v

        if alt[v]:
            seg.update(begin[v],alt[v][-1][0])

for i in range(Q):
    x,y,z = query[i]
    p = LCA[i]
    if z_on_path[i]!=-1:
        if alt_edge[z]==-1:
            print(-1)
        else:
            u,v,idx,cost = E[alt_edge[z]]
            pu,pv,_,_ = E[z]
            if rank[pu] > rank[pv]:
                pu,pv = pv,pu

            if z_on_path[i]==y:
                x,y = y,x

            if begin[pv] <= begin[u] <= end[pv]:
                res = dist(u,x) + dist(v,y) + cost
            else:
                res = dist(v,x) + dist(u,y) + cost
            res %= mod
            print(res)
    else:
        res = (depth[x] + depth[y] - 2 * depth[p]) % mod
        print(res)
0