package main

import (
  "bufio"
  "fmt"
  "os"
  "strconv"
  "strings"
)

func main() {
  input := Input{bufio.NewReaderSize(os.Stdin,100)}
  n,q := input.Next2Ints()
  tree := NewGraph(n)
  for i:=0;i<n-1;i++ {
    a,b,c,d := input.Next4Ints()
    a,b,c = a-1,b-1,c-1
    tree.Add(a,b,d,c)
    tree.Add(b,a,d,c)
  }
  lca := NewLca(tree)
  lca.Par()
  query := NewQueries(n,q)
  for i:=0;i<q;i++ {
    x,y,u,v := input.Next4Ints()
    x,u,v = x-1,u-1,v-1
    w := lca.Of(u,v)
    query.Add(u,i,x,1,y)
    query.Add(v,i,x,1,y)
    query.Add(w,i,x,-2,y)
    query.ans[i] = lca.Cost(u,v)
  }
  query.Dfs(tree,0,-1)
  for i:=0;i<q;i++ { fmt.Println(query.ans[i]) }
}

type Edge struct { to,cost,color int }
type Graph [][]Edge
func NewGraph(n int) Graph { return make([][]Edge,n) }
func(g Graph) AddEdge(from int,e Edge) { g[from] = append(g[from],e) }
func(g Graph) Add(from,to,cost,color int) { g.AddEdge(from,Edge{to,cost,color}) }

type Lca struct { g Graph;par [][]int;cost,depth []int }
func NewLca(g Graph) Lca {
  k := 0
  n := len(g)
  for (1<<uint(k)) < n { k++ }
  par := make([][]int,k)
  for i:=0;i<k;i++ { par[i] = make([]int,n) }
  cost := make([]int,n)
  depth := make([]int,n)
  return Lca{g,par,cost,depth}
}
func(l Lca) Dfs(v,p,d,c int) {
  l.par[0][v] = p
  l.depth[v] = d
  l.cost[v] = c
  for _,e := range l.g[v] {
    if e.to != p { l.Dfs(e.to,v,d+1,c+e.cost) }
  }
}
func(l Lca) Par() {
  l.Dfs(0,-1,0,0)
  n := len(l.cost)
  for k:=0;k<len(l.par)-1;k++ {
    for i:=0;i<n;i++ {
      if l.par[k][i] < 0 { l.par[k+1][i] = -1;continue }
      l.par[k+1][i] = l.par[k][l.par[k][i]]
    }
  }
}
func(l Lca) Distance(x,y int) int {
  return l.depth[x]+l.depth[y]-2*l.depth[l.Of(x,y)]
}
func(l Lca) Cost(x,y int) int {
  return l.cost[x]+l.cost[y]-2*l.cost[l.Of(x,y)]
}
func(l Lca) Of(x,y int) int {
  if l.depth[x] > l.depth[y] { x,y = y,x }
  for k:=0;k<len(l.par);k++ {
    if ((l.depth[y]-l.depth[x])>>uint(k))&1 == 1 {
      y = l.par[k][y]
    }
  }
  if x == y { return x }
  for k:=len(l.par)-1;k>-1;k-- {
    if l.par[k][x] != l.par[k][y] {
      x,y = l.par[k][x],l.par[k][y]
    }
  }
  return l.par[0][x]
}

type Query struct { id,color,coef,length int }
type Queries struct { qs [][]Query;sum,cnt,ans []int }
func NewQueries(n int,q int) Queries {
  sum := make([]int,n)
  cnt := make([]int,n)
  ans := make([]int,q)
  return Queries{make([][]Query,n),sum,cnt,ans}
}
func(q Queries) AddQuery(node int,qr Query) {
  q.qs[node] = append(q.qs[node],qr)
}
func(q Queries) Add(node,id,color,coef,length int) {
  q.AddQuery(node,Query{id,color,coef,length})
}
func(q Queries) Dfs(g Graph,v,p int) {
  for _,qr := range q.qs[v] {
    x := qr.length*q.cnt[qr.color]-q.sum[qr.color]
    q.ans[qr.id] += x*qr.coef
  }
  for _,e := range g[v] {
    if e.to == p { continue }
    q.cnt[e.color]++
    q.sum[e.color] += e.cost
    q.Dfs(g,e.to,v)
    q.cnt[e.color]--
    q.sum[e.color] -= e.cost
  }
}

type Input struct { reader *bufio.Reader }
func(i *Input) NextLine() string {
  var buffer []byte
  for {
    line,isPrefix,err := i.reader.ReadLine()
    if err != nil { panic(err) }
    buffer = append(buffer,line...)
    if !isPrefix { break }
  }
  return string(buffer)
}
func(i *Input) Next2Ints() (int,int) {
  s := strings.Fields(i.NextLine())
  x,_ := strconv.Atoi(s[0])
  y,_ := strconv.Atoi(s[1])
  return x,y
}
func(i *Input) Next4Ints() (int,int,int,int) {
  s := strings.Fields(i.NextLine())
  x,_ := strconv.Atoi(s[0])
  y,_ := strconv.Atoi(s[1])
  z,_ := strconv.Atoi(s[2])
  w,_ := strconv.Atoi(s[3])
  return x,y,z,w
}

Measured memory_bytes: 118784