// includes {{{
#include<iostream>
#include<iomanip>
#include<algorithm>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<tuple>
#include<cmath>
#include<random>
#include<cassert>
#include<bitset>
#include<cstdlib>
// #include<deque>
// #include<multiset>
// #include<cstring>
// #include<bits/stdc++.h>
// }}}
using namespace std;
using ll = long long;

// #undef DEBUG
// #define DEBUG
// DEBUG {{{
#include <array>
#include <deque>
#include <iostream>
#include <list>
#include <queue>
#include <stack>
#include <tuple>
#include <valarray>
#include <vector>
template < int n, class... T >
typename std::enable_if< (n >= sizeof...(T)) >::type __output_tuple(
    std::ostream &, std::tuple< T... > const &) {}
template < int n, class... T >
typename std::enable_if< (n < sizeof...(T)) >::type __output_tuple(
    std::ostream &os, std::tuple< T... > const &t) {
  os << (n == 0 ? "" : ", ") << std::get< n >(t);
  __output_tuple< n + 1 >(os, t);
}
template < class... T >
std::ostream &operator<<(std::ostream &os, std::tuple< T... > const &t) {
  os << "(";
  __output_tuple< 0 >(os, t);
  os << ")";
  return os;
}
template < class T, class U >
std::ostream &operator<<(std::ostream &os, std::pair< T, U > const &p) {
  os << "(" << p.first << ", " << p.second << ")";
  return os;
}
template < class T >
std::ostream &operator<<(std::ostream &os, const std::stack< T > &a) {
  os << "{";
  for(auto tmp = a; tmp.size(); tmp.pop())
    os << (a.size() == tmp.size() ? "" : ", ") << tmp.top();
  os << "}";
  return os;
}
template < class T, class Container, class Compare >
std::ostream &operator<<(std::ostream &os,
    std::priority_queue< T, Container, Compare > a) {
  os << "{ (top) ";
  while(a.size()) os << a.top() << (a.size() == 1 ? "" : ", "), a.pop();
  os << " }";
  return os;
}
template < class T, class Container >
std::ostream &operator<<(std::ostream &os, std::queue< T, Container > a) {
  os << "{ ";
  while(a.size()) os << a.front() << (a.size() == 1 ? "" : ", "), a.pop();
  os << " }";
  return os;
}
#ifdef DEBUG
#if !defined(DEBUG_OUT)
// #define DEBUG_OUT std::cerr
#endif
#define dump(...)                                                                \
  [&]() {                                                                        \
    auto __debug_tap = std::make_tuple(__VA_ARGS__);                             \
    DEBUG_OUT << "[" << __LINE__ << "] " << #__VA_ARGS__ << " = " << __debug_tap \
    << std::endl;                                                      \
  }()
template < class T >
inline void dump2D(T &d, size_t sizey, size_t sizex) {
  for(size_t i = 0; i < sizey; i++) {
    DEBUG_OUT << "\t";
    for(size_t j = 0; j < sizex; j++)
      DEBUG_OUT << d[i][j] << (j + 1 == sizex ? "" : "\t");
    DEBUG_OUT << std::endl;
  }
}
template < class T >
inline void dump1D(T &d, size_t sizey) {
  for(size_t i = 0; i < sizey; i++) {
    DEBUG_OUT << d[i] << (i + 1 == sizey ? "" : " ");
  }
  DEBUG_OUT << std::endl;
}
template <
class T, class = typename std::iterator_traits< decltype(begin(T())) >::value_type,
      class = typename std::enable_if< !std::is_same< T, std::string >::value >::type >
      std::ostream &operator<<(std::ostream &os, const T &a) {
        os << "{";
        for(auto ite = begin(a); ite != end(a); ++ite)
          os << (ite == begin(a) ? "" : ", ") << *ite;
        os << "}";
        return os;
      }
#else
#define dump(...) ((void) 42)
#define dump2D(...) ((void) 42)
#define dump1D(...) ((void) 42)
template <
class T, class = typename std::iterator_traits< decltype(begin(T())) >::value_type,
      class = typename std::enable_if< !std::is_same< T, std::string >::value >::type >
      std::ostream &operator<<(std::ostream &os, const T &a) {
        for(auto ite = begin(a); ite != end(a); ++ite)
          os << (ite == begin(a) ? "" : " ") << *ite;
        return os;
      }
#endif
// }}}


// MoTreeVertex(N, JUST Q, double k)
// favored : k = 2
// 1: addEdge
// 2: prebuild
// 3: insert
// 4: build
/// --- MoTreeVertex Library {{{ ///

struct MoTreeVertex {
  int n, logn, m;
  int width;
  int q = 0;
  vector< vector< int > > par;
  vector< int > dep;
  vector< int > in, vs;
  vector< vector< pair<int, int> > > g;
  vector< int8_t > flag;
  vector< int > le, ri, lcas, order;
  int nl = 0, nr = 0;
  int log(int x) {
    int h = 1;
    while((1 << h) < x) h++;
    return h;
  }
  MoTreeVertex(): n(0) {}
  MoTreeVertex(int n, int q, double k = 1)
    : n(n),
    logn(log(n)),
    m(2 * n - 1),
    width(int(k* m / sqrt(q) + 1.0)),
    // q(q),
    par(logn, vector< int >(n, -1)),
    dep(n),
    in(n),
    g(n),
    flag(n),
    le(q),
    ri(q),
    lcas(q),
    order(q) {
      vs.reserve(m);
    }
  inline void addEdge(int u, int v, int id = 0) {
    g[u].emplace_back(v, id);
    g[v].emplace_back(u, id);
  }
  inline void prebuild() {
    dfs(0, -1, 0);
    for(int k = 1; k < logn; k++)
      for(int i = 0; i < n; i++) {
        int p = par[k - 1][i];
        if(p == -1) continue;
        par[k][i] = par[k - 1][p];
      }
  }
  void dfs(int i, int p, int d) {
    dep[i] = d;
    par[0][i] = p;
    in[i] = vs.size();
    vs.emplace_back(i);
    for(auto to : g[i]) {
      int j, id;
      tie(j, id) = to;
      if(j != p) {
        dfs(j, i, d + 1);
        vs.emplace_back(j);
      }
    }
  }
  inline int lca(int u, int v) {
    if(dep[u] > dep[v]) swap(u, v);
    for(int k = logn - 1; k >= 0; k--) {
      int nv = par[k][v];
      if(nv != -1 && dep[nv] >= dep[u]) v = nv;
    }
    if(u == v) return u;
    for(int k = logn - 1; k >= 0; k--) {
      int nu = par[k][u], nv = par[k][v];
      if(nu != nv) u = nu, v = nv;
    }
    return par[0][u];
  }
  inline void insert(int u, int v) {
    if(in[u] > in[v]) swap(u, v);
    le[q] = in[u] + 1;
    ri[q] = in[v] + 1;
    lcas[q] = lca(u, v);
    order[q] = q;
    q++;
  }
  inline void build() {
    sort(begin(order), begin(order) + q, [&](int a, int b) {
        const int ab = le[a] / width, bb = le[b] / width;
        return ab != bb ? ab < bb : ab & 1 ? ri[a] < ri[b] : ri[b] < ri[a];
        });
    nl = nr = le[order[0]];
    for(int i = 0; i < q; i++) {
      if(i > 0) rem(lcas[order[i - 1]]);
      const int id = order[i];
      while(nl > le[id]) flip(vs[--nl]);
      while(nr < ri[id]) flip(vs[nr++]);
      while(nl < le[id]) flip(vs[nl++]);
      while(nr > ri[id]) flip(vs[--nr]);
      add(lcas[id]);
      next(id);
    }
  }
  inline void flip(int i) {
    if(flag[i] ^= 1)
      add(i);
    else
      rem(i);
  }
  inline void next(int id);
  inline void add(int i);
  inline void rem(int i);
};

/// }}}--- ///

const int N = 1e5;
std::vector<std::vector<tuple<int, int, int>>> g;
ll len = 0;
int n;
int q;
int cnt[N];
ll sum[N];
int ans[N];
ll x[N], y[N], u[N], v[N];
ll cost[N];
ll color[N];

MoTreeVertex mo;

inline void MoTreeVertex::next(int id) {
  dump(id, len, x[id], y[id], sum[x[id]], cnt[x[id]]);
  MoTreeVertex::rem(mo.lcas[id]);
  ans[id] = len - sum[x[id]] + cnt[x[id]] * y[id];
  MoTreeVertex::add(mo.lcas[id]);
}
inline void MoTreeVertex::add(int i) {
  dump("add", i);
  cnt[color[i]]++;
  sum[color[i]] += cost[i];
  len += cost[i];
}
inline void MoTreeVertex::rem(int i) {
  dump("rem", i);
  cnt[color[i]]--;
  sum[color[i]] -= cost[i];
  len -= cost[i];
}

void dfs(int i, int p = -1) {
  for(auto to : g[i]) {
    int j, col, ct;
    tie(j, col, ct) = to;
    if(j == p) continue;
    dfs(j, i);
    cost[j] = ct;
    color[j] = col;
  }
}

int main() {
  std::ios::sync_with_stdio(false), std::cin.tie(0);
  cin >> n >> q;
  dump(n, q);
  g.resize(n);
  mo = MoTreeVertex(n, q, 2);
  for(int i = 0; i < n - 1; i++) {
    int a, b, c, d; std::cin >> a >> b >> c >> d;
    a--; b--; c--;
    g[a].emplace_back(b, c, d);
    g[b].emplace_back(a, c, d);
    mo.addEdge(a, b);
  }
  dfs(0);
  mo.prebuild();
  for(int i = 0; i < q; i++) {
    cin >> x[i] >> y[i] >> u[i] >> v[i];
    x[i]--;
    u[i]--, v[i]--;
    mo.insert(u[i], v[i]);
  }
  mo.build();
  for(int i = 0; i < q; i++) {
    cout << ans[i] << "\n";
  }
  return 0;
}


Measured memory_bytes: 33656