#include <algorithm>
#include <bitset>
#include <cassert>
#include <cctype>
#include <cmath>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <deque>
#include <fstream>
#include <functional>
#include <iostream>
#include <limits>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <vector>
using namespace std;
using ll = long long;
#define fst first
#define snd second

/* clang-format off */
template <class T, size_t D> struct _vec { using type = vector<typename _vec<T, D - 1>::type>; };
template <class T> struct _vec<T, 0> { using type = T; };
template <class T, size_t D> using vec = typename _vec<T, D>::type;
template <class T> vector<T> make_v(size_t size, const T& init) { return vector<T>(size, init); }
template <class... Ts> auto make_v(size_t size, Ts... rest) { return vector<decltype(make_v(rest...))>(size, make_v(rest...)); }
template <class T> inline void chmin(T &a, const T& b) { if (b < a) a = b; }
template <class T> inline void chmax(T &a, const T& b) { if (b > a) a = b; }
/* clang-format on */

struct doubling_lca {
  int n, logn;
  vector<vector<int>> adj;
  doubling_lca(int n)
      : n(n), adj(n) {
    logn = 1;
    for (int k = 1; k < n; k *= 2) ++logn;
  }
  void add_edge(int s, int t) {
    adj[s].push_back(t);
    adj[t].push_back(s);
  }
  vector<vector<int>> parent;
  vector<int> rank, depth;
  void rootify(int r) {
    parent.assign(logn, vector<int>(n, r));
    rank.resize(n);
    depth.assign(n, 0);
    int id = 0;
    auto dfs = [&](auto& f, int u, int p) -> void {
      rank[u] = id++;
      parent[0][u] = p;
      for (int i = 0; i + 1 < logn; ++i)
        parent[i + 1][u] = parent[i][parent[i][u]];
      for (int v : adj[u])
        if (v != p) {
          depth[v] = depth[u] + 1;
          f(f, v, u);
        }
    };
    dfs(dfs, r, r);
  }
  int query(int u, int v) {
    if (depth[u] > depth[v]) swap(u, v);
    for (int i = depth[v] - depth[u], k = 0; i; i /= 2) {
      if (i & 1) v = parent[k][v];
      ++k;
    }
    if (u == v) return u;
    for (int i = logn - 1; i >= 0; --i) {
      if (parent[i][u] != parent[i][v]) {
        u = parent[i][u];
        v = parent[i][v];
      }
    }
    return parent[0][u];
  }
};

struct edge {
  int to;
  int color, weight;
};

struct query {
  int qi;
  int coef;
};

int main() {
#ifdef DEBUG
  ifstream ifs("in.txt");
  cin.rdbuf(ifs.rdbuf());
#endif
  int N, Q;
  while (cin >> N >> Q) {
    vec<edge, 2> G(N);
    doubling_lca lca(N);
    for (int i = 0; i < N - 1; i++) {
      int a, b, c, d;
      cin >> a >> b >> c >> d;
      --a;
      --b;
      --c;
      G[a].push_back({b, c, d});
      G[b].push_back({a, c, d});
      lca.add_edge(a, b);
    }
    lca.rootify(0);
    vector<int> qc(Q), qd(Q), qa(Q), qb(Q);
    for (int i = 0; i < Q; i++) {
      cin >> qc[i] >> qd[i] >> qa[i] >> qb[i];
      --qc[i];
      --qa[i];
      --qb[i];
    }
    vec<query, 2> queries(N);
    for (int i = 0; i < Q; i++) {
      int x = lca.query(qa[i], qb[i]);
      queries[qa[i]].push_back({i, +1});
      queries[qb[i]].push_back({i, +1});
      queries[x].push_back({i, -2});
    }
    vector<int> res(Q, 0);
    int sum = 0l;
    vector<int> colorSum(N - 1, 0), colorCnt(N - 1, 0);
    auto dfs = [&](auto& f, int v, int p = -1) -> void {
      for (auto& q : queries[v]) {
        int qi = q.qi;
        int color = qc[qi];
        int newWeight = qd[qi];
        int coef = q.coef;
        res[qi] += coef * (sum - colorSum[color] + colorCnt[color] * newWeight);
      }
      for (auto& e : G[v]) {
        if (e.to == p) continue;
        sum += e.weight;
        colorSum[e.color] += e.weight;
        ++colorCnt[e.color];
        f(f, e.to, v);
        --colorCnt[e.color];
        colorSum[e.color] -= e.weight;
        sum -= e.weight;
      }
    };
    dfs(dfs, 0);
    for (int x : res) cout << x << endl;
  }
  return 0;
}


Measured memory_bytes: 31736