#pragma GCC optimize("Ofast")
#define _USE_MATH_DEFINES
#include "bits/stdc++.h"
 
using namespace std;
 
using u8 = uint8_t;
using u16 = uint16_t;
using u32 = uint32_t;
using u64 = uint64_t;
using i8 = int8_t;
using i16 = int16_t;
using i32 = int32_t;
using i64 = int64_t;
 
constexpr char newl = '\n';
constexpr double eps = 1e-10;
 
#define FOR(i,a,b) for (int i = (a); i < (b); i++)
#define F0R(i,b) FOR(i,0,b)
#define RFO(i,a,b) for (int i = ((b)-1); i >=(a); i--)
#define RF0(i,b) RFO(i,0,b)
#define fi first
#define se second
#define debug(x) cout << #x << ": " << x << '\n';
#define rng(a) a.begin(),a.end()
#define rrng(a) a.rbegin(),a.rend()
 
template<typename T1, typename T2> inline void chmin(T1& a, T2 b) { if (a > b) a = b; }
template<typename T1, typename T2> inline void chmax(T1& a, T2 b) { if (a < b) a = b; }
template<class T> void Print(vector<T> v) {
  F0R(i, v.size()) {
    cout << v[i] << ' ';
  }
  cout << newl;
}
 
#if 1
 
 
// INSERT ABOVE HERE
signed main() {
  cin.tie(0);
  ios_base::sync_with_stdio(false);
 
  struct Link {
    int to, c, d;
    Link(int to, int c, int d) :to(to), c(c), d(d) {}
  };
 
  int N, Q;
  cin >> N >> Q;
  vector<vector<Link>> ls(N);
  F0R(i, N - 1) {
    int a, b, c, d;
    cin >> a >> b >> c >> d;
    a--; b--;
    ls[a].emplace_back(b, c, d);
    ls[b].emplace_back(a, c, d);
  }
 
  // ps[i][j] := 頂点 i の 2^j 番目の先祖
  vector<vector<int>> ps(N, vector<int>(18, -1));
 
  // depth
  vector<int> ds(N);
 
  auto dfs1 = [&](auto dfs1, int v, int p, int d)->void {
    ps[v][0] = p;
    ds[v] = d;
    F0R(i, 17) {
      if (ps[v][i] < 0) break;
      ps[v][i + 1] = ps[ps[v][i]][i];
    }
    ++d;
    for (auto& l : ls[v]) {
      if (l.to == p) continue;
      dfs1(dfs1, l.to, v, d);
    }
  };
  dfs1(dfs1, 0, -1, 0);
 
  // 頂点vのn番目の先祖
  auto par = [&](int v, int n) {
    F0R(i, 18) {
      if (n & 1) {
        v = ps[v][i];
        if (!n || v < 0) break;
      }
      n >>= 1;
    }
    return v;
  };
 
  // LCA
  auto lca = [&](int a, int b) {
    if (ds[a] < ds[b]) {
      b = par(b, ds[b] - ds[a]);
    }
    else if (ds[a] > ds[b]) {
      a = par(a, ds[a] - ds[b]);
    }
    if (a == b) return a;
    RF0(i, 18) {
      if (ps[a][i] != ps[b][i]) {
        a = ps[a][i];
        b = ps[b][i];
      }
    }
    return ps[a][0];
  };
 
  // debug
  /*
  F0R(i, N) {
    FOR(j, i + 1, N) {
      cout << "LCA of " << i << ", " << j << " = " << lca(i, j) << newl;
    }
  }
  //*/
 
  // 適当な頂点を根とした根付き木と考える。
  //
  // 頂点u,v間の距離 =
  // 根,頂点u間の距離 + 根,頂点v間の距離 - 2 * 根,頂点LCA(u,v)間の距離
 
  // ここまでの距離を足す
  vector<vector<int>> as(N);
  // ここまでの距離を引く
  vector<vector<int>> bs(N);
 
  struct Query {
    int x, y;
    int r = 0;
  };
  vector<Query> qs(Q);
  F0R(i, Q) {
    int u, v;
    cin >> qs[i].x >> qs[i].y>>u>>v;
    u--; v--;
    as[u].push_back(i);
    as[v].push_back(i);
    bs[lca(u, v)].push_back(i);
  }
 
  // 現在の頂点までの距離を、複数のパラメータで管理
  int dsum = 0; // 距離の合計
  vector<int> cs(N, 0); // 各色の数
  vector<int> es(N, 0); // 各色ごとの距離の合計
  auto dfs2 = [&](auto dfs2, int v, int p)->void {
    for (auto q : as[v]) {
      qs[q].r += dsum - es[qs[q].x] + cs[qs[q].x] * qs[q].y;
    }
    for (auto q : bs[v]) {
      qs[q].r -= 2 * (dsum - es[qs[q].x] + cs[qs[q].x] * qs[q].y);
    }
 
    for (auto &l : ls[v]) {
      if (l.to == p) continue;
      cs[l.c]++;
      es[l.c] += l.d;
      dsum += l.d;
      dfs2(dfs2, l.to, v);
      
      cs[l.c]--;
      
      es[l.c] -= l.d;
      dsum -= l.d;
    }
  };
  dfs2(dfs2, 0, -1);
 
  F0R(i, Q) {
    cout << qs[i].r << newl;
  }
}
#endif

Measured memory_bytes: 37680