Problem:


Score : 600 points

Problem Statement

There is a tree with N vertices numbered 1 to N.
The i-th edge in this tree connects Vertex a_i and Vertex b_i, and the color and length of that edge are c_i and d_i, respectively.
Here the color of each edge is represented by an integer between 1 and N-1 (inclusive). The same integer corresponds to the same color, and different integers correspond to different colors.

Answer the following Q queries:

Query j (1 \leq j \leq Q): assuming that the length of every edge whose color is x_j is changed to y_j, find the distance between Vertex u_j and Vertex v_j. (The changes of the lengths of edges do not affect the subsequent queries.)

Constraints

2 \leq N \leq 10^5

1 \leq Q \leq 10^5

1 \leq a_i, b_i \leq N

1 \leq c_i \leq N-1

1 \leq d_i \leq 10^4

1 \leq x_j \leq N-1

1 \leq y_j \leq 10^4

1 \leq u_j < v_j \leq N

The given graph is a tree.

All values in input are integers.

Input

Input is given from Standard Input in the following format:

N Q
a_1 b_1 c_1 d_1
:
a_{N-1} b_{N-1} c_{N-1} d_{N-1}
x_1 y_1 u_1 v_1
:
x_Q y_Q u_Q v_Q

Output

Print Q lines. The j-th line (1 \leq j \leq Q) should contain the answer to Query j.

Sample Input 1

5 3
1 2 1 10
1 3 2 20
2 4 4 30
5 2 1 40
1 100 1 4
1 100 1 5
3 1000 3 4

Sample Output 1

130
200
60

The graph in this input is as follows:

Here the edges of Color 1 are shown as solid red lines, the edge of Color 2 is shown as a bold green line, and the edge of Color 4 is shown as a blue dashed line.

Query 1: Assuming that the length of every edge whose color is 1 is changed to 100, the distance between Vertex 1 and Vertex 4 is 100 + 30 = 130.

Query 2: Assuming that the length of every edge whose color is 1 is changed to 100, the distance between Vertex 1 and Vertex 5 is 100 + 100 = 200.

Query 3: Assuming that the length of every edge whose color is 3 is changed to 1000 (there is no such edge), the distance between Vertex 3 and Vertex 4 is 20 + 10 + 30 = 60. Note that the edges of Color 1 now have their original lengths.



Sample input:
5 3
1 2 1 10
1 3 2 20
2 4 4 30
5 2 1 40
1 100 1 4
1 100 1 5
3 1000 3 4


Sample output:
130
200
60

Submission status: Wrong Answer

Solution code:
import sys
read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
readlines = sys.stdin.buffer.readlines

import numpy as np

N,Q = map(int,readline().split())
data = np.array(read().split(),np.int64)

ABCD = data[:4*N-4].reshape(-1,4).tolist()

graph = [[] for _ in range(N+1)]
for a,b,c,d in ABCD:
    graph[a].append((b,c,d))
    graph[b].append((a,c,d))

color = [0] * (N+1) # 自身と親を結ぶ辺の色
length = [0] * (N+1) # 自身と親を結ぶ辺の長さ

def EulerTour(graph,start=1):
    """
    1-indexed graph
    graphを破壊しているので場合によっては注意
    """
    V = len(graph)
    par = [0] * V
    depth = [0] * V; depth[start] = 0
    tour = [start]; st = [start]
    while st:
        x = st[-1]
        if not graph[x]:
            st.pop()
            tour.append(par[x])
            continue
        y,c,d = graph[x].pop()
        if y == par[x]:
            continue
        par[y] = x
        color[y] = c
        length[y] = d
        depth[y] = depth[x] + 1
        st.append(y)
        tour.append(y)
    return tour,depth

tour,depth = EulerTour(graph)

Ltour = len(tour)
tour_arr = np.array(tour)
depth_arr = np.array(depth)
tour_d = depth_arr[tour_arr]
idx = np.arange(len(depth))
idx[tour_arr] = np.arange(Ltour)

# depth最小を実現するインデックスのsparse tableを作る
sp = np.empty((Ltour.bit_length(),Ltour),np.int32)
sp[0] = np.arange(Ltour)
for n in range(1,Ltour.bit_length()):
    prev,width = sp[n-1],1<<(n-1)
    x = prev[:-width]; y = prev[width:]
    condition = tour_d[x] > tour_d[y]
    sp[n] = prev
    sp[n,:-width][condition] = y[condition]

def LCA(A,B):
    AB = np.vstack([A,B]).T
    LR = idx[AB]
    LR.sort(axis=1)
    # [L,R] におけるRmQ
    L = LR[:,0]; R = LR[:,1]
    x = R-L
    n = np.zeros_like(x) # 2^n <= R-L
    for _ in range(20):
        x >>= 1
        n[x>0] += 1
    x = sp[n,L]; y = sp[n,R-(1<<n)+1]
    return np.where(tour_d[x] < tour_d[y], tour_arr[x], tour_arr[y])

XYUV = data[4*N-4:]
U = XYUV[2::4]; V = XYUV[3::4]
lca = LCA(U,V)

answer = [0] * Q
task = [[] for _ in range(N+1)]
for i,((x,y,u,v),w) in enumerate(zip(XYUV.reshape(-1,4),lca)):
    # x,yの条件下での距離の何倍かをanswer[i]に加算する
    task[u].append((x,y,1,i))
    task[v].append((x,y,1,i))
    task[w].append((x,y,-2,i))

color_cnt = [0] * N
color_sum = [0] * N
d = 0 # いじらないときの距離

fr = 0,0,0,0 # 点、色、深さ
for fr,to in zip(tour,tour[1:]):
    d1 = depth[fr]; d2 = depth[to]
    if d1 > d2:
        # 上る前にクエリ処理
        pass
#        for x,y,coef,i in task[fr]:
#            answer[i] += coef * (d - color_sum[x] + color_cnt[x] * y)
    if d1 < d2:
        c = color[to]; l = length[to]
        color_cnt[c] += 1
        color_sum[c] += l; d += l
    else:
        c = color[fr]; l = length[fr]
        color_cnt[c] -= 1
        color_sum[c] -= l; d -= l

print('\n'.join(map(str,answer)))

Submission status: Wrong Answer

Solution code:
import sys
input = sys.stdin.readline
sys.setrecursionlimit(10**7)
import numpy as np

N,Q = map(int,input().split())
graph = [[] for _ in range(N+1)]
for _ in range(N-1):
    a,b,c,d = map(int,input().split())
    graph[a].append((b,c,d))
    graph[b].append((a,c,d))
query = [[int(x) for x in input().split()] for _ in range(Q)]

def euler_tour(x, tour_v, tour_d, depth = 0, parent=None):
    tour_v.append(x)
    tour_d.append(depth)
    for y, c, d in graph[x]:
        if y == parent:
            continue
        euler_tour(y, tour_v, tour_d, depth + 1, parent = x)
        tour_v.append(x)
        tour_d.append(depth)

tour_v = []
tour_d = []
euler_tour(1, tour_v, tour_d)
tour_d_arr = np.array(tour_d)
v_to_i = {v:i for i,v in enumerate(tour_v)}
v_to_d = dict(zip(tour_v, tour_d))

# sparse table
# 各インデックスから、2^i 項目分見て、一番depthの小さいインデックス
L = len(tour_v)
U = L.bit_length()
sp = [np.arange(L)]
for i in range(1,U):
    prev = sp[-1]
    width = 1 << (i-1)
    n1 = prev[:-width]
    n2 = prev[width:]
    sp.append(np.where(tour_d_arr[n1] < tour_d_arr[n2], n1, n2))

def LCA(x,y):
    ix = v_to_i[x]
    iy = v_to_i[y]
    if ix > iy:
        ix,iy = iy,ix
    items = iy - ix + 1
    L = items.bit_length() - 1
    n1 = sp[L][ix]
    n2 = sp[L][iy - (1 << L) + 1]
    n = n1 if tour_d[n1] < tour_d[n2] else n2
    return tour_v[n]

tasks = [[] for _ in range(N+1)]
for i,(x,y,u,v) in enumerate(query):
    tasks[u].append((i,x,y,1))
    tasks[v].append((i,x,y,1))
    tasks[LCA(u,v)].append((i,x,y,-2))

answer = [0] * Q

Submission status: Wrong Answer

Solution code:
import sys
read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
readlines = sys.stdin.buffer.readlines

import numpy as np

N,Q = map(int,readline().split())
data = np.array(read().split(),np.int64)

ABCD = data[:4*N-4].reshape(-1,4).tolist()

graph = [[] for _ in range(N+1)]
for a,b,c,d in ABCD:
    graph[a].append((b,c,d))
    graph[b].append((a,c,d))

color = [0] * (N+1) # 自身と親を結ぶ辺の色
length = [0] * (N+1) # 自身と親を結ぶ辺の長さ

def EulerTour(graph,start=1):
    """
    1-indexed graph
    graphを破壊しているので場合によっては注意
    """
    V = len(graph)
    par = [0] * V
    depth = [0] * V; depth[start] = 0
    tour = [start]; st = [start]
    while st:
        x = st[-1]
        if not graph[x]:
            st.pop()
            tour.append(par[x])
            continue
        y,c,d = graph[x].pop()
        if y == par[x]:
            continue
        par[y] = x
        color[y] = c
        length[y] = d
        depth[y] = depth[x] + 1
        st.append(y)
        tour.append(y)
    return tour,depth

tour,depth = EulerTour(graph)

Ltour = len(tour)
tour_arr = np.array(tour)
depth_arr = np.array(depth)
tour_d = depth_arr[tour_arr]
idx = np.arange(len(depth))
idx[tour_arr] = np.arange(Ltour)

# depth最小を実現するインデックスのsparse tableを作る
sp = np.empty((Ltour.bit_length(),Ltour),np.int32)
sp[0] = np.arange(Ltour)
for n in range(1,Ltour.bit_length()):
    prev,width = sp[n-1],1<<(n-1)
    x = prev[:-width]; y = prev[width:]
    condition = tour_d[x] > tour_d[y]
    sp[n] = prev
    sp[n,:-width][condition] = y[condition]

def LCA(A,B):
    AB = np.vstack([A,B]).T
    LR = idx[AB]
    LR.sort(axis=1)
    # [L,R] におけるRmQ
    L = LR[:,0]; R = LR[:,1]
    x = R-L
    n = np.zeros_like(x) # 2^n <= R-L
    for _ in range(20):
        x >>= 1
        n[x>0] += 1
    x = sp[n,L]; y = sp[n,R-(1<<n)+1]
    return np.where(tour_d[x] < tour_d[y], tour_arr[x], tour_arr[y])

XYUV = data[4*N-4:]
U = XYUV[2::4]; V = XYUV[3::4]
lca = LCA(U,V)

answer = [0] * Q
task = [[] for _ in range(N+1)]
for i,((x,y,u,v),w) in enumerate(zip(XYUV.reshape(-1,4),lca)):
    # x,yの条件下での距離の何倍かをanswer[i]に加算する
    task[u].append((x,y,1,i))
    task[v].append((x,y,1,i))
    task[w].append((x,y,-2,i))

Submission status: Wrong Answer

Solution code:
import sys
read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
readlines = sys.stdin.buffer.readlines

import numpy as np

N,Q = map(int,readline().split())
data = np.array(read().split(),np.int64)

ABCD = data[:4*N-4].reshape(-1,4).tolist()

graph = [[] for _ in range(N+1)]
for a,b,c,d in ABCD:
    graph[a].append((b,c,d))
    graph[b].append((a,c,d))

color = [0] * (N+1) # 自身と親を結ぶ辺の色
length = [0] * (N+1) # 自身と親を結ぶ辺の長さ

def EulerTour(graph,start=1):
    """
    1-indexed graph
    graphを破壊しているので場合によっては注意
    """
    V = len(graph)
    par = [0] * V
    depth = [0] * V; depth[start] = 0
    tour = [start]; st = [start]
    while st:
        x = st[-1]
        if not graph[x]:
            st.pop()
            tour.append(par[x])
            continue
        y,c,d = graph[x].pop()
        if y == par[x]:
            continue
        par[y] = x
        color[y] = c
        length[y] = d
        depth[y] = depth[x] + 1
        st.append(y)
        tour.append(y)
    return tour,depth

tour,depth = EulerTour(graph)

Ltour = len(tour)
tour_arr = np.array(tour)
depth_arr = np.array(depth)
tour_d = depth_arr[tour_arr]
idx = np.arange(len(depth))
idx[tour_arr] = np.arange(Ltour)

# depth最小を実現するインデックスのsparse tableを作る
sp = np.empty((Ltour.bit_length(),Ltour),np.int32)
sp[0] = np.arange(Ltour)
for n in range(1,Ltour.bit_length()):
    prev,width = sp[n-1],1<<(n-1)
    x = prev[:-width]; y = prev[width:]
    condition = tour_d[x] > tour_d[y]
    sp[n] = prev
    sp[n,:-width][condition] = y[condition]

def LCA(A,B):
    AB = np.vstack([A,B]).T
    LR = idx[AB]
    LR.sort(axis=1)
    # [L,R] におけるRmQ
    L = LR[:,0]; R = LR[:,1]
    x = R-L
    n = np.zeros_like(x) # 2^n <= R-L
    for _ in range(20):
        x >>= 1
        n[x>0] += 1
    x = sp[n,L]; y = sp[n,R-(1<<n)+1]
    return np.where(tour_d[x] < tour_d[y], tour_arr[x], tour_arr[y])

Submission status: Wrong Answer

Solution code:
import sys
input = sys.stdin.readline
sys.setrecursionlimit(10**7)
import numpy as np

N,Q = map(int,input().split())
graph = [[] for _ in range(N+1)]
for _ in range(N-1):
    a,b,c,d = map(int,input().split())
    graph[a].append((b,c,d))
    graph[b].append((a,c,d))
query = [[int(x) for x in input().split()] for _ in range(Q)]

def euler_tour(x, tour_v, tour_d, depth = 0, parent=None):
    tour_v.append(x)
    tour_d.append(depth)
    for y, c, d in graph[x]:
        if y == parent:
            continue
        euler_tour(y, tour_v, tour_d, depth + 1, parent = x)
        tour_v.append(x)
        tour_d.append(depth)

tour_v = []
tour_d = []
euler_tour(1, tour_v, tour_d)
tour_d_arr = np.array(tour_d)
v_to_i = {v:i for i,v in enumerate(tour_v)}
v_to_d = dict(zip(tour_v, tour_d))

# sparse table
# 各インデックスから、2^i 項目分見て、一番depthの小さいインデックス
L = len(tour_v)
U = L.bit_length()
sp = [np.arange(L)]
for i in range(1,U):
    prev = sp[-1]
    width = 1 << (i-1)
    n1 = prev[:-width]
    n2 = prev[width:]
    sp.append(np.where(tour_d_arr[n1] < tour_d_arr[n2], n1, n2))

def LCA(x,y):
    ix = v_to_i[x]
    iy = v_to_i[y]
    if ix > iy:
        ix,iy = iy,ix
    items = iy - ix + 1
    L = items.bit_length() - 1
    n1 = sp[L][ix]
    n2 = sp[L][iy - (1 << L) + 1]
    n = n1 if tour_d[n1] < tour_d[n2] else n2
    return tour_v[n]

Submission status: Wrong Answer

Solution code:
import sys
from collections import defaultdict
readline = sys.stdin.readline
 
N, Q = map(int, readline().split())


def process():
    INF = (N, None)
    M = 2*N
    M0 = 2**(M-1).bit_length()
    data = [INF]*(2*M0)

    G = [[] for _ in range(N)]
    dp = {}
    for v in range(N-1):
        a, b, c, d = map(int, readline().split())
        a, b = a-1, b-1
        G[a].append(b)
        G[b].append(a)
        dp[(min(a,b), max(a,b))] = c, d

    S = [0]*(2*N)
    F = [0]*(2*N)
    stack = [0] + G[0][::-1]
    visited = set([0])
    depth = [0]*N
    depthh = [0]*N
    mmn = [[0] for _ in range(N)]
    msn = [[0] for _ in range(N)]
    iin = [[] for _ in range(N)]
    ccs = [0]*N
    path = [0]
    ii = 0
    d = 0
    dd = 0

    while True:
        if len(stack) == 0:
            break
        v = stack.pop()
        if v in visited:
            continue
        ii += 1
        if v >=0:
            visited.add(v)
            cc, dpd = dp[(min(v,path[-1]), max(v,path[-1]))]
            F[v] = ii
            S[ii] = v
            d += 1
            dd += dpd
            depth[v] = d
            depthh[v] = dd
            ccs[v] = cc

            mmn[cc].append(mmn[cc][-1]+1)
            msn[cc].append(msn[cc][-1]+dpd)
            iin[cc].append(v)

            path.append(v)
            stack += [-v] + G[v][::-1]
        else:
            cc, dpd = dp[(min(path[-1], path[-2]), max(path[-1],path[-2]))]
            dd -= dpd
            mmn[cc].append(mmn[cc][-1]-1)
            iin[cc].append(-path[-1])
            msn[cc].append(msn[cc][-1]-dpd)
            F[-path[-1]] = ii
            path.pop()
            S[ii] = path[-1]
            d -= 1
    print(S)
    
    for i, v in enumerate(S):
        data[M0-1+i] = (depth[v], i)
    for i in range(M0-2, -1, -1):
        data[i] = min(data[2*i+1], data[2*i+2])

    for q in range(Q):
        x, y, u, v = map(int, readline().split())
        u, v = u-1, v-1
        fu = F[u]; fv = F[v]
        if fu > fv:
            fu, fv = fv, fu

        minx = INF
        a, b = fu, fv+1
        a += M0; b += M0
        while a < b:
            if b & 1:
                b -= 1
                minx = min(minx, data[b-1])
            if a & 1:
                minx = min(minx, data[a-1])
                a += 1
            a >>= 1; b >>= 1
        cc = S[minx[1]]
        
        if len(mmn[x])-1 == 0:
            diff = 0
        else:
            ll, mm, ms, lncc = iin[x], mmn[x], msn[x], len(mmn[x])-2
            uvcs = []
            for target_i in [F[u], F[v], F[cc]]:
                ind, lw, hw =  (len(mmn[x])-2)//2, 0, len(mmn[x]) - 2
                if target_i < F[ll[0]] or target_i >= F[ll[lncc]]:
                    uvcs.append((0,0))
                else:
                    while True:
                        if F[ll[ind]] <= target_i:
                            if target_i < F[ll[ind+1]]:
                                uvcs.append((mm[ind+1], ms[ind+1]))
                                break
                            ind, lw = (ind+1 + hw)//2, ind+1
                            continue
                        ind, hw = (ind-1 + lw)//2, ind-1
            diff = (uvcs[0][0] + uvcs[1][0] - 2 * uvcs[2][0]) * y - (uvcs[0][1] + uvcs[1][1] - 2 * uvcs[2][1])
        print(depthh[u] + depthh[v] - 2*depthh[cc] + diff)

if __name__ == '__main__':
    process()

Submission status: Wrong Answer

Solution code:
import sys
sys.setrecursionlimit(10**7)

N, Q = map(int, input().split())
edge = [[] for _ in range(N+1)]
for _ in range(N-1):
        a, b, c, d = map(int, input().split())
        edge[a].append((b, c, d))
        edge[b].append((a, c, d))

depth = [0] * (N+1)
U = 17
ancestor = [[0] * (U+1) for _ in range(N+1)]

q = [(1, 0, 0)]
while q:
        qq = []
        for x, d, parent in q:
                depth[x] = d
                ax = ancestor[x]
                ax[0] = parent
                for i in range(d.bit_length()-1):
                        ax[i+1] = ancestor[ax[i]][i]

                for y, _, _ in edge[x]:
                        if y == parent:
                                continue
                        qq.append((y, d+1, x))
        q = qq

def lca(x, y):
        dx = depth[x]
        dy = depth[y]
        if dx > dy:
                x, y = y, x
                dx, dy = dy, dx
        diff = dy - dx
        while diff:
                step = diff & (-diff)
                y = ancestor[y][step.bit_length()-1]
                diff -= step
        while x!=y:
                j = 0
                while ancestor[x][j] != ancestor[y][j]:
                        j += 1
                if j==0:
                        return ancestor[x][0]
                x = ancestor[x][j-1]
                y = ancestor[y][j-1]
        return x

task = [[] for _ in range(N+1)]
for i in range(Q):
        x, y, u, v = map(int, input().split())
        task[u].append((i, x, y, 1))
        task[v].append((i, x, y, 1))
        task[lca(u, v)].append((i, x, y, -2))

answer = [0] * Q

def dfs(x=1, sums=[0]*(N+1), nums=[0]*(N+1), total=0, parent=0):
        for i, c, d, coef in task[x]:
                answer[i] += coef * (total - sums[c] + nums[c]*d)
        for y, c, d in edge[x]:
                if y == parent:
                        continue
                sums[c] += d
                nums[c] += 1
                total += d
                dfs(y, sums, nums, total, x)
                sums[c] -= d
                nums[c] -= d
                total -= d
        return

dfs()

print('\n'.join(map(str, answer)))

Submission status: Wrong Answer

Solution code:
import sys
input = sys.stdin.readline
sys.setrecursionlimit(10**7)

N, Q = map(int, input().split())
graph = [[] for _ in range(N+1)]
for _ in range(N-1):
    a, b, c, d = map(int, input().split())
    graph[a].append((b, c, d))
    graph[b].append((a, c, d))
query = [[int(x) for x in input().split()] for _ in range(Q)]

depth = [0] * (N+1)
U = 17
ancestor = [[0] * (U+1) for _ in range(N+1)]

q = [(1, 0, 0)]
while q:
    qq = []
    for x, d, parent in q:
        depth[x] = d
        ax = ancestor[x]
        ax[0] = parent
        for i in range(d.bit_length()-1):
            ax[i+1] = ancestor[ax[i]][i]
        for y, _, _ in graph[x]:
            if y == parent:
                continue
            qq.append((y, d+1, x))
    q = qq

def LCA(x, y):
    dx = depth[x]
    dy = depth[y]
    if dx > dy:
        x, y = y, x
        dx, dy = dy, dx
    diff = dy - dx
    while diff:
        step = diff & (-diff)
        y = ancestor[y][step.bit_length()-1]
        diff -= step
    while x != y:
        j = 0
        while ancestor[x][j] != ancestor[y][j]:
            j += 1
        if j == 0:
            return ancestor[x][0]
        x = ancestor[x][j-1]
        y = ancestor[y][j-1]
    return x

tasks = [[] for _ in range(N+1)]
for i, (x, y, u, v) in enumerate(query):
    tasks[u].append((i, x, y, 1))
    tasks[v].append((i, x, y, 1))
    tasks[LCA(u, v)].append((i, x, y, -2))

answer = [0] * Q

def dfs(x = 1, sums = [0] * (N+1), nums = [0] * (N+1), total = 0, parent = 0):
    for i, c, d, coef in tasks[x]:
        answer[i] += coef * (total - sums[c] + nums[c] * d)
    for y, c, d in graph[x]:
        if y == parent:
            continue
        sums[c] += d
        nums[c] += 1
        total += d
        dfs(y, sums, nums, total, x)
        sums[c] -= d
        nums[c] -= d
        total -= d
    return

dfs()

print('\n'.join(map(str, answer)))

Submission status: Wrong Answer

Solution code:
#!/usr/bin/env python3
import sys
from collections.abc import Iterable
from math import *
from itertools import *
from collections import *
from functools import *
from operator import *
try:
    from math import gcd
except Exception:
    from fractions import gcd

class DGraph:
    def __init__(self, n, edges):
        self._vertice = [{} for _ in range(n)]
        for e in edges:
            self._vertice[e[0]][e[1]] = e[2] if len(e) == 3 else 1

    def __len__(self):
        return len(self._vertice)

    def edges(self, n=None):
        srcs = range(len(self)) if n is None else [n]
        return sum([[(s, d, c) for d, c in self._vertice[s].items()] for s in srcs], [])

    def transpose(self):
        tedges = [(t, f, c) for f, t, c in self.edges()]
        return DGraph(len(self), tedges)

    def cost(self, src, dst):
        return self._vertice[src].get(dst, float('inf'))

class Graph(DGraph):
    def __init__(self, n, edges):
        nd_edges = edges + [(d, s, c) for s, d, c in edges]
        super().__init__(n, nd_edges)

    def transpose(self):
        return self

def dfs(g, src):
    visited = [False] * len(g)
    stack = [(src, (0, -1, {}))]
    while stack:
        n, (c, p, acc) = stack.pop()
        if visited[n]:
            continue
        visited[n] = True

        for _, d, (dd, cc) in g.edges(n):
            _acc = dict(acc)
            if cc not in _acc:
                _acc[cc] = (0, 0)
            _acc[cc] = (_acc[cc][0] + 1, _acc[cc][1] + dd)
            stack.append((d, (c + 1, n, _acc)))
        yield n, c, p, acc


def solve(N: int, Q: int, a: "List[int]", b: "List[int]", c: "List[int]", d: "List[int]", x: "List[int]", y: "List[int]", u: "List[int]", v: "List[int]"):
    es = []
    for _a, _b, _c, _d in zip(a, b, c, d):
        es.append((_a - 1, _b - 1, (_d, _c)))

    h = int(ceil(log2(N)))
    g = Graph(N, es)
    ds = [-1] * N
    ps = [[-1] * h for _ in range(N)]
    accs = [{}] * N
    for i, d, p, acc in dfs(g, 0):
        ds[i] = d
        ps[i][0] = p
        accs[i] = acc

    for j in range(h - 1):
        for i in range(N):
            ps[i][j + 1] = ps[ps[i][j]][j]

    ret = []
    for _x, _y, _u, _v in zip(x, y, u, v):
        uu = _u - 1
        vv = _v - 1
        while ds[uu] < ds[vv]:
            vv = ps[vv][0]
        while ds[vv] < ds[uu]:
            uu = ps[uu][0]
        if uu == vv:
            lca = uu
        else:
            for i in range(h-1, 0, -1):
                if ps[uu][i] != ps[vv][i]:
                    uu = ps[uu][i]
                    vv = ps[vv][i]
            lca = ps[uu][0]

        du = sum([ddd for _, ddd in accs[_u - 1].values()])
        if _x in accs[_u - 1]:
            du += _y * accs[_u - 1][_x][0] - accs[_u - 1][_x][1]
        dv = sum([ddd for _, ddd in accs[_v - 1].values()])
        if _x in accs[_v - 1]:
            dv += _y * accs[_v - 1][_x][0] - accs[_v - 1][_x][1]
        dlca = sum([ddd for _, ddd in accs[lca].values()])
        if _x in accs[lca]:
            dlca += _y * accs[lca][_x][0] - accs[lca][_x][1]
        dist = du + dv - 2 * dlca
        ret.append(dist)
    return ret


def main():
    def iterate_tokens():
        for line in sys.stdin:
            for word in line.split():
                yield word
    tokens = iterate_tokens()
    N = int(next(tokens))  # type: int
    Q = int(next(tokens))  # type: int
    a = [int()] * (N-1)  # type: "List[int]" 
    b = [int()] * (N-1)  # type: "List[int]" 
    c = [int()] * (N-1)  # type: "List[int]" 
    d = [int()] * (N-1)  # type: "List[int]" 
    for i in range(N-1):
        a[i] = int(next(tokens))
        b[i] = int(next(tokens))
        c[i] = int(next(tokens))
        d[i] = int(next(tokens))
    x = [int()] * (Q)  # type: "List[int]" 
    y = [int()] * (Q)  # type: "List[int]" 
    u = [int()] * (Q)  # type: "List[int]" 
    v = [int()] * (Q)  # type: "List[int]" 
    for i in range(Q):
        x[i] = int(next(tokens))
        y[i] = int(next(tokens))
        u[i] = int(next(tokens))
        v[i] = int(next(tokens))
    result = solve(N, Q, a, b, c, d, x, y, u, v)
    if isinstance(result, Iterable) and not isinstance(result, str):
        result = '\n'.join([str(v) for v in result])
    print(result)

if __name__ == '__main__':
    main()

Submission status: Wrong Answer

Solution code:
#!/usr/bin/env python3
import sys
from collections.abc import Iterable
from math import *
from itertools import *
from collections import *
from functools import *
from operator import *
try:
    from math import gcd
except Exception:
    from fractions import gcd

class DGraph:
    def __init__(self, n, edges):
        self._vertice = [{} for _ in range(n)]
        for e in edges:
            self._vertice[e[0]][e[1]] = e[2] if len(e) == 3 else 1

    def __len__(self):
        return len(self._vertice)

    def edges(self, n=None):
        srcs = range(len(self)) if n is None else [n]
        return sum([[(s, d, c) for d, c in self._vertice[s].items()] for s in srcs], [])

    def transpose(self):
        tedges = [(t, f, c) for f, t, c in self.edges()]
        return DGraph(len(self), tedges)

    def cost(self, src, dst):
        return self._vertice[src].get(dst, float('inf'))

class Graph(DGraph):
    def __init__(self, n, edges):
        nd_edges = edges + [(d, s, c) for s, d, c in edges]
        super().__init__(n, nd_edges)

    def transpose(self):
        return self

def dfs(g, src):
    visited = [False] * len(g)
    stack = [(src, (0, -1, {}))]
    while stack:
        n, (c, p, acc) = stack.pop()
        if visited[n]:
            continue
        visited[n] = True

        for _, d, (dd, cc) in g.edges(n):
            _acc = dict(acc)
            if cc not in _acc:
                _acc[cc] = (0, 0)
            _acc[cc] = (_acc[cc][0] + 1, _acc[cc][1] + dd)
            stack.append((d, (c + 1, n, _acc)))
        yield n, c, p, acc


def solve(N: int, Q: int, a: "List[int]", b: "List[int]", c: "List[int]", d: "List[int]", x: "List[int]", y: "List[int]", u: "List[int]", v: "List[int]"):
    es = []
    for _a, _b, _c, _d in zip(a, b, c, d):
        es.append((_a - 1, _b - 1, (_d, _c)))

    h = int(ceil(log2(N)))
    g = Graph(N, es)
    ds = [-1] * N
    ps = [[-1] * h for _ in range(N)]
    accs = [{}] * N
    for i, d, p, acc in dfs(g, 0):
        ds[i] = d
        ps[i][0] = p
        accs[i] = acc

    for i in range(N):
        for j in range(h - 1):
            ps[i][j + 1] = ps[ps[i][j]][j]


    ret = []
    for _x, _y, _u, _v in zip(x, y, u, v):
        uu = _u - 1
        vv = _v - 1
        while ds[uu] < ds[vv]:
            vv = ps[vv][0]
        while ds[vv] < ds[uu]:
            uu = ps[uu][0]
        if uu == vv:
            lca = uu
        else:
            for i in range(h-1, 0, -1):
                if ps[uu][i] != ps[vv][i]:
                    uu = ps[uu][i]
                    vv = ps[vv][i]
            lca = ps[uu][0]

        du = sum([ddd for _, ddd in accs[_u - 1].values()])
        if _x in accs[_u - 1]:
            du += _y * accs[_u - 1][_x][0] - accs[_u - 1][_x][1]
        dv = sum([ddd for _, ddd in accs[_v - 1].values()])
        if _x in accs[_v - 1]:
            dv += _y * accs[_v - 1][_x][0] - accs[_v - 1][_x][1]
        dlca = sum([ddd for _, ddd in accs[lca].values()])
        if _x in accs[lca]:
            dlca += _y * accs[lca][_x][0] - accs[lca][_x][1]
        dist = du + dv - 2 * dlca
        ret.append(dist)
    return ret


def main():
    def iterate_tokens():
        for line in sys.stdin:
            for word in line.split():
                yield word
    tokens = iterate_tokens()
    N = int(next(tokens))  # type: int
    Q = int(next(tokens))  # type: int
    a = [int()] * (N-1)  # type: "List[int]" 
    b = [int()] * (N-1)  # type: "List[int]" 
    c = [int()] * (N-1)  # type: "List[int]" 
    d = [int()] * (N-1)  # type: "List[int]" 
    for i in range(N-1):
        a[i] = int(next(tokens))
        b[i] = int(next(tokens))
        c[i] = int(next(tokens))
        d[i] = int(next(tokens))
    x = [int()] * (Q)  # type: "List[int]" 
    y = [int()] * (Q)  # type: "List[int]" 
    u = [int()] * (Q)  # type: "List[int]" 
    v = [int()] * (Q)  # type: "List[int]" 
    for i in range(Q):
        x[i] = int(next(tokens))
        y[i] = int(next(tokens))
        u[i] = int(next(tokens))
        v[i] = int(next(tokens))
    result = solve(N, Q, a, b, c, d, x, y, u, v)
    if isinstance(result, Iterable) and not isinstance(result, str):
        result = '\n'.join([str(v) for v in result])
    print(result)

if __name__ == '__main__':
    main()