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.

Solution (Python):
def examA():
    N = DI()/dec(7)
    ans = N
    print(N)
    return

def examB():
    ans = 0
    print(ans)
    return

def examC():
    ans = 0
    print(ans)
    return

def examD():
    ans = 0
    print(ans)
    return

def examE():
    ans = 0
    print(ans)
    return

def examF():
    class LCA(object):
        def __init__(self, G, root=0):
            self.G = G
            self.root = root
            self.n = len(G)
            self.logn = (self.n - 1).bit_length()
            self.depth = [-1 if i != root else 0 for i in range(self.n)]
            self.parent = [[-1] * self.n for _ in range(self.logn)]
            self.W = [-1 if i != root else 0 for i in range(self.n)]
            self.dfs()
            self.doubling()
            
            
            

        def dfs(self):
            que = [self.root]
            while que:
                u = que.pop()
                for v, (d, c) in self.G[u].items():
                    if self.depth[v] == -1:
                        self.depth[v] = self.depth[u] + 1
                        self.parent[0][v] = u
                        self.W[v] = self.W[u] + d
                        que += [v]

        def doubling(self):
            for i in range(1, self.logn):
                for v in range(self.n):
                    if self.parent[i - 1][v] != -1:
                        self.parent[i][v] = self.parent[i - 1][self.parent[i - 1][v]]

        def get(self, u, v):
            if self.depth[v] < self.depth[u]:
                u, v = v, u
            du = self.depth[u]
            dv = self.depth[v]
            for i in range(self.logn):  
                if (dv - du) >> i & 1:
                    v = self.parent[i][v]
            if u == v: return u  
            for i in range(self.logn - 1, -1, -1):  
                pu, pv = self.parent[i][u], self.parent[i][v]
                if pu != pv:
                    u, v = pu, pv
            return self.parent[0][u]

    
    def euler_tour(G, root=0):
        n = len(G)
        euler = []
        dq = deque([root])
        dq2 = deque()
        visited = [0] * n
        while dq:
            u = dq.pop()
            euler += [u]
            if visited[u]:
                continue
            for v in G[u].keys():
                if visited[v]:
                    dq += [v]
                
                else:
                    dq2 += [v]
            dq.extend(dq2)
            dq2 = deque()
            visited[u] = 1
        return euler

    N, q = LI()
    V = [{} for _ in range(N)]
    for _ in range(N - 1):
        a, b, c, d = LI()
        V[a - 1][b - 1] = (d, c)
        V[b - 1][a - 1] = (d, c)
    lca = LCA(V)
    
    
    
    colors = [set() for _ in range(N)]
    Q = [LI()for _ in range(q)]
    for x, y, u, v in Q:
        u -= 1; v -= 1
        a = lca.get(u,v)
        colors[u].add(x)
        colors[v].add(x)
        colors[a].add(x)
    
    
    ET = euler_tour(V)
    

    
    Q_color = [{}for _ in range(N)]
    Q_length = [{}for _ in range(N)]
    for color in colors[0]:
        Q_color[0][color] = 0
        Q_length[0][color] = 0

    
    S_color = defaultdict(int)
    
    S_length = defaultdict(int)

    visited = [False]*N
    visited[0] = True
    for i in range(len(ET)-1):
        now,ne = ET[i],ET[i+1]
        d,c = V[now][ne]
        
        if visited[ne]:
            S_color[c] -= 1
            S_length[c] -= d
            continue
        else:
            S_color[c] += 1
            S_length[c] += d

        for color in colors[ne]:
            Q_color[ne][color] = S_color[color]
            Q_length[ne][color] = S_length[color]

        visited[ne] = True

    ans = [0]*q
    for i,(x,y,u,v) in enumerate(Q):
        u -= 1; v -= 1
        a = lca.get(u, v)
        child_1 = lca.W[u] + (Q_color[u][x]*y - Q_length[u][x])
        child_2 = lca.W[v] + (Q_color[v][x]*y - Q_length[v][x])
        parent = lca.W[a] + (Q_color[a][x]*y - Q_length[a][x])
        

        ans[i] = child_1 + child_2 - parent * 2

    for v in ans:
        print(v)
    return


from decimal import getcontext,Decimal as dec
import sys,bisect,itertools,heapq,math,random
from copy import deepcopy
from heapq import heappop,heappush,heapify
from collections import Counter,defaultdict,deque
read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
readlines = sys.stdin.buffer.readlines
def I(): return int(input())
def LI(): return list(map(int,sys.stdin.readline().split()))
def DI(): return dec(input())
def LDI(): return list(map(dec,sys.stdin.readline().split()))
def LSI(): return list(map(str,sys.stdin.readline().split()))
def LS(): return sys.stdin.readline().split()
def SI(): return sys.stdin.readline().strip()
global mod,mod2,inf,alphabet,_ep
mod = 10**9 + 7
mod2 = 998244353
inf = 10**18
_ep = dec("0.000000000001")
alphabet = [chr(ord('a') + i) for i in range(26)]
alphabet_convert = {chr(ord('a') + i): i for i in range(26)}

getcontext().prec = 28

sys.setrecursionlimit(10**7)

if __name__ == '__main__':
    examF()

"""
142
12 9 1445 0 1
asd dfg hj o o
aidn
"""

Solution (Python):
def examA():
    N = DI()/dec(7)
    ans = N
    print(N)
    return

def examB():
    ans = 0
    print(ans)
    return

def examC():
    ans = 0
    print(ans)
    return

def examD():
    ans = 0
    print(ans)
    return

def examE():
    ans = 0
    print(ans)
    return

def examF():
    class LCA(object):
        def __init__(self, G, root=0):
            self.G = G
            self.root = root
            self.n = len(G)
            self.logn = (self.n - 1).bit_length()
            self.depth = [-1 if i != root else 0 for i in range(self.n)]
            self.parent = [[-1] * self.n for _ in range(self.logn)]
            self.W = [-1 if i != root else 0 for i in range(self.n)]
            self.dfs()
            self.doubling()
            
            
            

        def dfs(self):
            que = [self.root]
            while que:
                u = que.pop()
                for v, (d, c) in self.G[u].items():
                    if self.depth[v] == -1:
                        self.depth[v] = self.depth[u] + 1
                        self.parent[0][v] = u
                        self.W[v] = self.W[u] + d
                        que += [v]

        def doubling(self):
            for i in range(1, self.logn):
                for v in range(self.n):
                    if self.parent[i - 1][v] != -1:
                        self.parent[i][v] = self.parent[i - 1][self.parent[i - 1][v]]

        def get(self, u, v):
            if self.depth[v] < self.depth[u]:
                u, v = v, u
            du = self.depth[u]
            dv = self.depth[v]
            for i in range(self.logn):  
                if (dv - du) >> i & 1:
                    v = self.parent[i][v]
            if u == v: return u  
            for i in range(self.logn - 1, -1, -1):  
                pu, pv = self.parent[i][u], self.parent[i][v]
                if pu != pv:
                    u, v = pu, pv
            return self.parent[0][u]

    
    def euler_tour(G, root=0):
        n = len(G)
        euler = []
        dq = deque([root])
        dq2 = deque()
        visited = [0] * n
        while dq:
            u = dq.pop()
            euler += [u]
            if visited[u]:
                continue
            for v in G[u].keys():
                if visited[v]:
                    dq += [v]
                
                else:
                    dq2 += [v]
            dq.extend(dq2)
            dq2 = deque()
            visited[u] = 1
        return euler

    N, q = LI()
    V = [{} for _ in range(N)]
    for _ in range(N - 1):
        a, b, c, d = LI()
        V[a - 1][b - 1] = (d, c)
        V[b - 1][a - 1] = (d, c)
    lca = LCA(V)
    
    
    
    colors = [set() for _ in range(N)]
    Q = [LI()for _ in range(q)]
    for x, y, u, v in Q:
        u -= 1; v -= 1
        a = lca.get(u,v)
        colors[u].add(x)
        colors[v].add(x)
        colors[a].add(x)
    
    
    ET = euler_tour(V)
    

    
    Q_color = [{}for _ in range(N)]
    Q_length = [{}for _ in range(N)]
    for color in colors[0]:
        Q_color[0][color] = 0
        Q_length[0][color] = 0

    
    S_color = defaultdict(int)
    
    S_length = defaultdict(int)

    visited = [False]*N
    visited[0] = True
    for i in range(len(ET)-1):
        now,ne = ET[i],ET[i+1]
        d,c = V[now][ne]
        
        if visited[ne]:
            S_color[c] -= 1
            S_length[c] -= d
            continue
        else:
            S_color[c] += 1
            S_length[c] += d

        for color in colors[ne]:
            Q_color[ne][color] = S_color[color]
            Q_length[ne][color] = S_length[color]

        visited[ne] = True

    ans = [0]*q
    for i,(x,y,u,v) in enumerate(Q):
        u -= 1; v -= 1
        a = lca.get(u, v)
        child_1 = lca.W[u] + (Q_color[u][x]*y - Q_length[u][x])
        child_2 = lca.W[v] + (Q_color[v][x]*y - Q_length[v][x])
        parent = lca.W[a] + (Q_color[a][x]*y - Q_length[a][x])
        

        ans[i] = child_1 + child_2 - parent * 2

    for v in ans:
        print(v)
    return


from decimal import getcontext,Decimal as dec
import sys,bisect,itertools,heapq,math,random
from copy import deepcopy
from heapq import heappop,heappush,heapify
from collections import Counter,defaultdict,deque
read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
readlines = sys.stdin.buffer.readlines
def I(): return int(input())
def LI(): return list(map(int,sys.stdin.readline().split()))
def DI(): return dec(input())
def LDI(): return list(map(dec,sys.stdin.readline().split()))
def LSI(): return list(map(str,sys.stdin.readline().split()))
def LS(): return sys.stdin.readline().split()
def SI(): return sys.stdin.readline().strip()
global mod,mod2,inf,alphabet,_ep
mod = 10**9 + 7
mod2 = 998244353
inf = 10**18
_ep = dec("0.000000000001")
alphabet = [chr(ord('a') + i) for i in range(26)]
alphabet_convert = {chr(ord('a') + i): i for i in range(26)}

getcontext().prec = 28

sys.setrecursionlimit(10**7)

if __name__ == '__main__':
    examF()

"""
142
12 9 1445 0 1
asd dfg hj o o
aidn
"""

Solution (Python):
import sys

input=sys.stdin.readline
sys.setrecursionlimit(10**7)

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

prv=[-1]*N
depth=[0]*N
dist=[0 for i in range(N)]
def dfs(v,pv):
    prv[v]=pv
    for nv,color,weight in edge[v]:
        if nv!=pv:
            depth[nv]=depth[v]+1
            dist[nv]=dist[v]+weight
            dfs(nv,v)

dfs(0,-1)

LV = (N-1).bit_length()
def construct(prv):
    kprv = [prv]
    S = prv
    for k in range(LV):
        T = [0]*N
        for i in range(N):
            if S[i] is None:
                continue
            T[i] = S[S[i]]
        kprv.append(T)
        S = T
    return kprv

kprv=construct(prv)

def lca(u, v):
    dd = depth[v] - depth[u]
    if dd < 0:
        u, v = v, u
        dd = -dd

    
    for k in range(LV+1):
        if dd & 1:
            v = kprv[k][v]
        dd >>= 1

    
    if u == v:
        return u

    for k in range(LV-1, -1, -1):
        pu = kprv[k][u]; pv = kprv[k][v]
        if pu != pv:
            u = pu; v = pv

    
    return kprv[0][u]

query=[]
q=[[] for i in range(N)]
data={}
for i in range(Q):
    x,y,u,v=map(int,input().split())
    LCA=lca(u-1,v-1)
    query.append((x,y,u-1,v-1,LCA))
    q[u-1].append(x)
    q[v-1].append(x)
    q[LCA].append(x)

num=[0 for i in range(N)]
cdist=[0 for i in range(N)]

def dfsc(v,pv,color,weight):
    pn=num[color]
    num[color]+=1
    pd=cdist[color]
    cdist[color]+=weight
    for x in q[v]:
        data[(v,x)]=(0,0)
        data[(v,x)]=(num[x],cdist[x])

    for nv,ncolor,nweight in edge[v]:
        if nv!=pv:
            dfsc(nv,v,ncolor,nweight)

    num[color]=pn
    cdist[color]=pd



dfsc(0,0,0,0)

for x,y,u,v,LCA in query:
    d1=dist[LCA]-data[(LCA,x)][1]+data[(LCA,x)][0]*y
    d2=dist[u]-data[(u,x)][1]+data[(u,x)][0]*y
    d3=dist[v]-data[(v,x)][1]+data[(v,x)][0]*y
    print(d2-d1+d3-d1)

Solution (Python):
import sys,bisect
from collections import deque
def I():return int(input())
def LI():return [int(i) for i in input().split()]
def LI_():return [int(i)-1 for i in input().split()]
def GI(V,E,ls=None,Directed=False,index=1):
    org_inp=[];g=[[] for i in range(V)]
    FromStdin=True if ls==None else False
    for i in range(E):
        if FromStdin:
            inp=LI()
            org_inp.append(inp)
        else:
            inp=ls[i]
        if len(inp)==2:
            a,b=inp;c=1
        else:
            a,b,c=inp
        if index==1:a-=1;b-=1
        aa=(a,c);bb=(b,c);g[a].append(bb)
        if not Directed:g[b].append(aa)
    return g,org_inp
def TI(n):return GI(n,n-1)
mo=10**9+7
inf=float('inf')
input=lambda: sys.stdin.readline().rstrip()

class Tree:
    def __init__(self,inp_size=None,init=True):
        self.LCA_init_stat=False
        self.ETtable=[]
        if init:
            self.stdin(inp_size)
        return

    def stdin(self,inp_size=None,index=1):
        if inp_size==None:
            self.size=int(input())
        else:
            self.size=inp_size
        self.edges,_=GI(self.size,self.size-1,index=index)
        return
    
    def listin(self,ls,index=0):
        self.size=len(ls)+1
        self.edges,_=GI(self.size,self.size-1,ls,index=index)
        return

    def __str__(self):
        return  str(self.edges)

    def dfs(self,x,func=lambda prv,nx,dist:prv+dist,root_v=0):
        q=deque()
        q.append(x)
        v=[-1]*self.size
        v[x]=root_v
        while q:
            c=q.pop()
            for nb,d in self.edges[c]:
                if v[nb]==-1:
                    q.append(nb)
                    v[nb]=func(v[c],nb,d)
        return v

    def EulerTour(self,x):
        q=deque()
        q.append(x)
        self.depth=[None]*self.size
        self.depth[x]=0
        self.ETtable=[]
        self.ETdepth=[]
        self.ETin=[-1]*self.size
        self.ETout=[-1]*self.size
        cnt=0
        while q:
            c=q.pop()
            if c<0:
                ce=~c
            else:
                ce=c
                for nb,d in self.edges[ce]:
                    if self.depth[nb]==None:
                        q.append(~ce)
                        q.append(nb)
                        self.depth[nb]=self.depth[ce]+1
            self.ETtable.append(ce)
            self.ETdepth.append(self.depth[ce])
            if self.ETin[ce]==-1:
                self.ETin[ce]=cnt
            else:
                self.ETout[ce]=cnt
            cnt+=1
        return
    
    def LCA_init(self,root):
        self.EulerTour(root)
        self.st=SparseTable(self.ETdepth,init_func=min,init_idl=inf)
        self.LCA_init_stat=True
        return
    
    def LCA(self,root,x,y):
        if self.LCA_init_stat==False:
            self.LCA_init(root)
        xin,xout=self.ETin[x],self.ETout[x]
        yin,yout=self.ETin[y],self.ETout[y]
        a=min(xin,yin)
        b=max(xout,yout,xin,yin)
        id_of_min_dep_in_et=self.st.query_id(a,b+1)
        return self.ETtable[id_of_min_dep_in_et]

class SparseTable:
    def __init__(self,ls,init_func=min,init_idl=float('inf')):
        self.func=init_func
        self.idl=init_idl
        self.size=len(ls)
        self.N0=self.size.bit_length()
        self.table=[ls[:]]
        self.index=[list(range(self.size))]
        self.lg=[0]*(self.size+1)
        
        for i in range(2,self.size+1):
            self.lg[i]=self.lg[i>>1]+1

        for i in range(self.N0):
            tmp=[self.func(self.table[i][j],self.table[i][min(j+(1<<i),self.size-1)]) for j in range(self.size)]
            tmp_id=[self.index[i][j] if self.table[i][j]==self.func(self.table[i][j],self.table[i][min(j+(1<<i),self.size-1)]) else self.index[i][min(j+(1<<i),self.size-1)] for j in range(self.size)]
            self.table+=[tmp]
            self.index+=[tmp_id]
    def query(self,l,r):
        N=self.lg[r-l]
        return self.func(self.table[N][l],self.table[N][r-(1<<N)])
    def query_id(self,l,r):
        N=self.lg[r-l]
        a,b=self.index[N][l],self.index[N][r-(1<<N)]
        if self.table[0][a]==self.func(self.table[N][l],self.table[N][r-(1<<N)]):
            b=a
        return b
ans=0

n,q=LI()
ls=deque()
col=dict()
e_len=dict()
for i in range(n-1):
    a,b,c,d=LI_()
    d+=1
    ls+=[(a,b,d)]
    
    eid=a*n+b if a<b else b*n+a
    col[eid]=c
    e_len[eid]=d
    
tr=Tree(init=False)
tr.listin(ls,index=0)
 
root=0
dist=tr.dfs(root)
tr.EulerTour(0)
dep=tr.depth
et=tr.ETtable
 
ad=[[0] for i in range(n)]
an=[[0] for i in range(n)]
index=[[] for i in range(n)]
for i in range(2*n-1-1):
    a,b=et[i],et[i+1]
    sign=1 if dep[a]<dep[b] else -1
    eid=a*n+b if a<b else b*n+a
    c=col[eid]
    dd=e_len[eid]*sign
    an[c]+=[an[c][-1]+sign]
    ad[c]+=[ad[c][-1]+dd]
    index[c]+=[i]
for i in range(n):
    ad[i]+=[ad[i][-1]]
    an[i]+=[an[i][-1]]

for i in range(q):
    x,y,u,v=LI_()
    y+=1
    lca=tr.LCA(root,u,v)
    path=dist[u]+dist[v]-dist[lca]*2
    
    ui=bisect.bisect_left(index[x],tr.ETin[u])
    vi=bisect.bisect_left(index[x],tr.ETin[v])
    ai=bisect.bisect_left(index[x],tr.ETin[lca])
    
    c_path=ad[x][ui]+ad[x][vi]-ad[x][ai]*2
    c_n=an[x][ui]+an[x][vi]-an[x][ai]*2
    ans=path-c_path+c_n*y
    print(ans)

Solution (Python):
class Tree(): 
    def __init__(self, n, edge):
        self.n = n
        self.tree = [[] for _ in range(n)]
        for e in edge:
            self.tree[e[0] - 1].append((e[1] - 1, e[2] - 1, e[3]))
            self.tree[e[1] - 1].append((e[0] - 1, e[2] - 1, e[3]))

    def setroot(self, root):
        self.root = root
        self.parent = [None for _ in range(self.n)]
        self.parent[root] = -1
        self.depth = [None for _ in range(self.n)]
        self.depth[root] = 0
        self.distance = [None for _ in range(self.n)]
        self.distance[root] = 0
        self.order = []
        self.order.append(root)
        self.color = [None for _ in range(self.n)]
        self.cost = [0 for _ in range(self.n)]
        self.size = [1 for _ in range(self.n)]
        stack = [root]
        while stack:
            node = stack.pop()
            for adj, color, cost in self.tree[node]:
                if self.parent[adj] is None:
                    self.parent[adj] = node
                    self.depth[adj] = self.depth[node] + 1
                    self.distance[adj] = self.distance[node] + cost
                    self.color[adj] = color
                    self.cost[adj] = cost
                    self.order.append(adj)
                    stack.append(adj)
        for node in self.order[::-1]:
            for adj, color, cost in self.tree[node]:
                if self.parent[node] == adj:
                    continue
                self.size[node] += self.size[adj]

    def heavylight_decomposition(self):
        self.order = [None for _ in range(self.n)]
        self.head = [None for _ in range(self.n)]
        self.head[self.root] = self.root
        self.next = [None for _ in range(self.n)]
        stack = [self.root]
        order = 0
        while stack:
            node = stack.pop()
            self.order[node] = order
            order += 1
            maxsize = 0
            for adj, color, cost in self.tree[node]:
                if self.parent[node] == adj:
                    continue
                if maxsize < self.size[adj]:
                    maxsize = self.size[adj]
                    self.next[node] = adj
            for adj, color, cost in self.tree[node]:
                if self.parent[node] == adj or self.next[node] == adj:
                    continue
                self.head[adj] = adj
                stack.append(adj)
            if self.next[node] is not None:
                self.head[self.next[node]] = self.head[node]
                stack.append(self.next[node])

    def range_hld(self, u, v, edge=False):
        res = []
        while True:
            if self.order[u] > self.order[v]: u, v = v, u
            if self.head[u] != self.head[v]:
                res.append((self.order[self.head[v]], self.order[v] + 1))
                v = self.parent[self.head[v]]
            else:
                res.append((self.order[u] + edge, self.order[v] + 1))
                return res

    def subtree_hld(self, u):
        return self.order[u], self.order[u] + self.size[u]

    def lca_hld(self, u, v):
        while True:
            if self.order[u] > self.order[v]: u, v = v, u
            if self.head[u] != self.head[v]:
                v = self.parent[self.head[v]]
            else:
                return u

class SegmentTree():
    def __init__(self, arr, func=min, ie=2**63):
        self.h = (len(arr) - 1).bit_length()
        self.n = 2**self.h
        self.ie = ie
        self.func = func
        self.tree = [ie for _ in range(2 * self.n)]
        for i in range(len(arr)):
            self.tree[self.n + i] = arr[i]
        for i in range(1, self.n)[::-1]:
            self.tree[i] = func(self.tree[2 * i], self.tree[2 * i + 1])

    def set(self, idx, x):
        idx += self.n
        self.tree[idx] = x
        while idx:
            idx >>= 1
            self.tree[idx] = self.func(self.tree[2 * idx], self.tree[2 * idx + 1])

    def query(self, lt, rt):
        lt += self.n
        rt += self.n
        vl = vr = self.ie
        while rt - lt > 0:
            if lt & 1:
                vl = self.func(vl, self.tree[lt])
                lt += 1
            if rt & 1:
                rt -= 1
                vr = self.func(self.tree[rt], vr)
            lt >>= 1
            rt >>= 1
        return self.func(vl, vr)

import sys
input = sys.stdin.readline

N, Q = map(int, input().split())

edge = [tuple(map(int, input().split())) for _ in range(N - 1)]
query = [tuple(map(int, input().split())) for _ in range(Q)]

tree = Tree(N, edge)
tree.setroot(0)
tree.heavylight_decomposition()

arr = [None for _ in range(N)]

for i in range(N):
    arr[tree.order[i]] = (tree.cost[i], 0)

def func(x, y):
    x0, x1 = x
    y0, y1 = y
    return x0 + y0, x1 + y1

ie = (0, 0)

st = SegmentTree(arr, func, ie)

query_color = [[] for _ in range(N)]

for j in range(Q):
    x, y, u, v = query[j]
    query_color[x - 1].append((y, u, v, j))

node_color = [[] for _ in range(N)]

for i in range(1, N):
    node_color[tree.color[i]].append(i)

res = [0 for _ in range(Q)]

for i in range(N):
    for node in node_color[i]:
        st.set(tree.order[node], (0, 1))

    for y, u, v, j in query_color[i]:
        for lt, rt in tree.range_hld(u - 1, v - 1, True):
            d, k = st.query(lt, rt)
            res[j] += d + k * y

    for node in node_color[i]:
        st.set(tree.order[node], (tree.cost[node], 0))

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

Solution (Python):
import sys,bisect,string,math,time,functools,random
from heapq import heappush,heappop,heapify
from collections import deque,defaultdict,Counter
from itertools import permutations,combinations,groupby
def Golf():*a,=map(int,open(0))
def I():return int(input())
def S_():return input()
def IS():return input().split()
def LS():return [i for i in input().split()]
def LI():return [int(i) for i in input().split()]
def LI_():return [int(i)-1 for i in input().split()]
def NI(n):return [int(input()) for i in range(n)]
def NI_(n):return [int(input())-1 for i in range(n)]
def StoLI():return [ord(i)-97 for i in input()]
def ItoS(n):return chr(n+97)
def LtoS(ls):return ''.join([chr(i+97) for i in ls])
def GI(V,E,ls=None,Directed=False,index=1):
    org_inp=[];g=[[] for i in range(V)]
    FromStdin=True if ls==None else False
    for i in range(E):
        if FromStdin:
            inp=LI()
            org_inp.append(inp)
        else:
            inp=ls[i]
        if len(inp)==2:
            a,b=inp;c=1
        else:
            a,b,c=inp
        if index==1:a-=1;b-=1
        aa=(a,c);bb=(b,c);g[a].append(bb)
        if not Directed:g[b].append(aa)
    return g,org_inp
def GGI(h,w,search=None,replacement_of_found='.',mp_def={'

    mp=[boundary]*(w+2);found={}
    for i in range(h):
        s=input()
        for char in search:
            if char in s:
                found[char]=((i+1)*(w+2)+s.index(char)+1)
                mp_def[char]=mp_def[replacement_of_found]
        mp+=[boundary]+[mp_def[j] for j in s]+[boundary]
    mp+=[boundary]*(w+2)
    return h+2,w+2,mp,found
def TI(n):return GI(n,n-1)
def bit_combination(k,n=2):
    rt=[]
    for tb in range(n**k):
        s=[tb//(n**bt)%n for bt in range(k)];rt+=[s]
    return rt
def show(*inp,end='\n'):
    if show_flg:print(*inp,end=end)

YN=['YES','NO'];Yn=['Yes','No']
mo=10**9+7
inf=float('inf')
l_alp=string.ascii_lowercase

input=lambda: sys.stdin.readline().rstrip()

class Tree:
    def __init__(self,inp_size=None,init=True):
        self.LCA_init_stat=False
        self.ETtable=[]
        if init:
            self.stdin(inp_size)
        return

    def stdin(self,inp_size=None,index=1):
        if inp_size==None:
            self.size=int(input())
        else:
            self.size=inp_size
        self.edges,_=GI(self.size,self.size-1,index=index)
        return
    
    def listin(self,ls,index=0):
        self.size=len(ls)+1
        self.edges,_=GI(self.size,self.size-1,ls,index=index)
        return

    def __str__(self):
        return  str(self.edges)

    def dfs(self,x,func=lambda prv,nx,dist:prv+dist,root_v=0):
        q=deque()
        q.append(x)
        v=[-1]*self.size
        v[x]=root_v
        while q:
            c=q.pop()
            for nb,d in self.edges[c]:
                if v[nb]==-1:
                    q.append(nb)
                    v[nb]=func(v[c],nb,d)
        return v

    def EulerTour(self,x):
        q=deque()
        q.append(x)
        self.depth=[None]*self.size
        self.depth[x]=0
        self.ETtable=[]
        self.ETdepth=[]
        self.ETin=[-1]*self.size
        self.ETout=[-1]*self.size
        cnt=0
        while q:
            c=q.pop()
            if c<0:
                ce=~c
            else:
                ce=c
                for nb,d in self.edges[ce]:
                    if self.depth[nb]==None:
                        q.append(~ce)
                        q.append(nb)
                        self.depth[nb]=self.depth[ce]+1
            self.ETtable.append(ce)
            self.ETdepth.append(self.depth[ce])
            if self.ETin[ce]==-1:
                self.ETin[ce]=cnt
            else:
                self.ETout[ce]=cnt
            cnt+=1
        return
    
    def LCA_init(self,root):
        self.EulerTour(root)
        self.st=SparseTable(self.ETdepth,init_func=min,init_idl=inf)
        self.LCA_init_stat=True
        return
    
    def LCA(self,root,x,y):
        if self.LCA_init_stat==False:
            self.LCA_init(root)
        xin,xout=self.ETin[x],self.ETout[x]
        yin,yout=self.ETin[y],self.ETout[y]
        a=min(xin,yin)
        b=max(xout,yout,xin,yin)
        id_of_min_dep_in_et=self.st.query_id(a,b+1)
        return self.ETtable[id_of_min_dep_in_et]

class SparseTable: 
    def __init__(self,ls,init_func=min,init_idl=float('inf')):
        self.func=init_func
        self.idl=init_idl
        self.size=len(ls)
        self.N0=self.size.bit_length()
        self.table=[ls[:]]
        self.index=[list(range(self.size))]
        self.lg=[0]*(self.size+1)
        
        for i in range(2,self.size+1):
            self.lg[i]=self.lg[i>>1]+1

        for i in range(self.N0):
            tmp=[self.func(self.table[i][j],self.table[i][min(j+(1<<i),self.size-1)]) for j in range(self.size)]
            tmp_id=[self.index[i][j] if self.table[i][j]==self.func(self.table[i][j],self.table[i][min(j+(1<<i),self.size-1)]) else self.index[i][min(j+(1<<i),self.size-1)] for j in range(self.size)]
            self.table+=[tmp]
            self.index+=[tmp_id]
    
    
    def query(self,l,r):
        
        N=self.lg[r-l]
        return self.func(self.table[N][l],self.table[N][r-(1<<N)])
    
    
    def query_id(self,l,r):
        
        N=self.lg[r-l]
        a,b=self.index[N][l],self.index[N][r-(1<<N)]
        if self.table[0][a]==self.func(self.table[N][l],self.table[N][r-(1<<N)]):
            b=a
        return b
    
    def __str__(self):
        return str(self.table[0])
        
    def print(self):
        for i in self.table:
            print(*i)

show_flg=False
show_flg=True
ans=0


 
n,q=LI()
ls=deque()
col=dict()
e_len=dict()
for i in range(n-1):
    a,b,c,d=LI_()
    d+=1
    ls+=[(a,b,d)]
    
    eid=a*n+b if a<b else b*n+a
    col[eid]=c
    e_len[eid]=d
    
tr=Tree(init=False)
tr.listin(ls,index=0)
 
root=0
dist=tr.dfs(root)
tr.EulerTour(0)
dep=tr.depth
et=tr.ETtable
 
ad=[[0] for i in range(n)]
an=[[0] for i in range(n)]
index=[[] for i in range(n)]
for i in range(2*n-1-1):
    a,b=et[i],et[i+1]
    sign=1 if dep[a]<dep[b] else -1
    eid=a*n+b if a<b else b*n+a
    c=col[eid]
    dd=e_len[eid]*sign
    an[c]+=[an[c][-1]+sign]
    ad[c]+=[ad[c][-1]+dd]
    index[c]+=[i]
for i in range(n):
    ad[i]+=[ad[i][-1]]
    an[i]+=[an[i][-1]]

for i in range(q):
    x,y,u,v=LI_()
    y+=1
    lca=tr.LCA(root,u,v)
    path=dist[u]+dist[v]-dist[lca]*2
    
    ui=bisect.bisect_left(index[x],tr.ETin[u])
    vi=bisect.bisect_left(index[x],tr.ETin[v])
    ai=bisect.bisect_left(index[x],tr.ETin[lca])
    
    c_path=ad[x][ui]+ad[x][vi]-ad[x][ai]*2
    c_n=an[x][ui]+an[x][vi]-an[x][ai]*2
    ans=path-c_path+c_n*y
    print(ans)