#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <deque>
#include <queue>
#include <array>
#include <set>
#include <map>
#include <cmath>
#include <algorithm>
#include <numeric>
#include <cassert>
#include <utility>
#include <tuple>
#include <functional>
#include <bitset>
#include <cstdint>

using namespace std;
using i64 = int64_t;
using i32 = int32_t;
template<class T, class U> void init_n(vector<T>& v, size_t n, U x) 
{ v = vector<T>(n, x); }
template<class T> void init_n(vector<T>& v, size_t n) { init_n(v, n, T()); }
template<class T> void read_n(vector<T>& v, size_t n, size_t o = 0) 
{ v = vector<T>(n+o); for (size_t i=o; i<n+o; ++i) cin >> v[i]; }
template<class T> void read_n(T a[], size_t n, size_t o = 0)
{ for (size_t i=o; i<n+o; ++i) cin >> a[i]; }
template<class T> T gabs(const T& x) { return max(x, -x); }
#define abs gabs

struct Lca {
  // doubling
  vector<vector<int>> par;
  vector<int> depth;

  Lca() {}
  template<class G>
  Lca(const G& g, int root) { init(g, root); }
  template<class G>
  void init(const G& g, int root) {
    par.resize(g.size());
    depth.resize(g.size());
    init_dfs(g, root, -1);
  }
  template<class G>
  void init_dfs(const G& g, int u, int p) {
    if (p >= 0) {
      depth[u] = depth[p] + 1;
      size_t k = 0;
      int q = p;
      while (true) {
        par[u].push_back(q);
        if (k >= par[q].size()) break;
        q = par[q][k];
        ++k;
      }
    }
    for (auto e : g[u]) {
      if (e.v != p) init_dfs(g, e.v, u);
    }
  }
  int get(int u, int v) {
    if (depth[u] < depth[v]) swap(u, v);
    while (depth[u] > depth[v]) {
      size_t k = 1;
      for (; depth[u] - (1 << k) > depth[v]; ++k);
      u = par[u][k - 1];
    }
    while (u != v) {
      size_t k = 1;
      for (; k < par[u].size() && par[u][k] != par[v][k]; ++k);
      u = par[u][k - 1];
      v = par[v][k - 1];
    }
    return u;
  }
};

struct Edge {
  i64 v, c, d;
};
struct Query {
  i64 x, y, u, v;
};
struct Data {
  i64 cnt, sum;
};
i64 n, q;
vector<vector<Edge>> g;
vector<Query> qs;
vector<map<i64, Data>> data;
vector<i64> dist, c_cnt, c_sum;
void dfs(i64 u, i64 p, i64 d) {
  dist[u] = d;
  for (auto& p : data[u]) {
    i64 c = p.first;
    p.second = { c_cnt[c], c_sum[c] };
  }
  for (auto e : g[u]) {
    if (e.v == p) continue;
    c_cnt[e.c]++;
    c_sum[e.c] += e.d;
    dfs(e.v, u, d + e.d);
    c_cnt[e.c]--;
    c_sum[e.c] -= e.d;
  }
}
i64 f(i64 u, i64 c, i64 y) {
  auto d = data[u][c];
  return dist[u] - d.sum + d.cnt * y;
}

int main() {
  cin >> n >> q;
  init_n(g, n + 1);
  for (i64 i = 0; i < n - 1; ++i) {
    i64 a, b, c, d;
    cin >> a >> b >> c >> d;
    g[a].push_back({b, c, d});
    g[b].push_back({a, c, d});
  }
  Lca lca(g, 1);
  init_n(data, n + 1);
  for (i64 i = 0; i < q; ++i) {
    i64 x, y, u, v;
    cin >> x >> y >> u >> v;
    qs.push_back({x, y, u, v});
    data[u][x];
    data[v][x];
    data[lca.get(u, v)][x];
  }
  init_n(dist, n + 1);
  init_n(c_cnt, n + 1);
  init_n(c_sum, n + 1);
  dfs(1, -1, 0);
  for (i64 i = 0; i < q; ++i) {
    auto t = qs[i];
    i64 a = lca.get(t.u, t.v);
    i64 ans = f(t.u, t.x, t.y) + f(t.v, t.x, t.y) - 2 * f(a, t.x, t.y);
    cout << ans << endl;
  }
  return 0;
}


Measured memory_bytes: 48492