// clang-format off
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define stoi stoll
using pii = pair<int,int>;
using vi = vector<int>;
using vvi = vector<vi>;
#define all(c) begin(c), end(c)
#define rall(c) rbegin(c), rend(c)
#define fore(x, c) for(auto &&x : c)
#define rep(i, a, n) for(int i = a, i##len = (int)(n); i < i##len; ++i)
#define rrep(i, a, n) for(int i = (int)(n - 1); i >= a; --i)
#define sz(c) ((int)c.size())
#define contains(c, x) (c.find(x) != end(c))
#define inseg(l, x, r) ((l) <= (x) && (x) < (r))
#define dump(...)
#define pb push_back
#define eb emplace_back
#define _ 0
const signed INF_ = 1001001001; const long long INF = 1001001001001001001LL;
const int DX[9] = {0,1,0,-1,1,1,-1,-1,0}, DY[9] = {-1,0,1,0,-1,1,1,-1,0};
template<class T> ostream& operator<<(ostream &os, const vector<T> &v) {
  for (auto i = begin(v); i != end(v); i++) os<<*i<<(i==end(v)-1?"":" ");return os;}
template<class T> istream& operator>>(istream &is, vector<T> &v) {
  for (auto i = begin(v); i != end(v); i++) is>>*i;return is;}
template<class T,class U> istream& operator>>(istream &is, pair<T,U> &p) {
  is>>p.first>>p.second;return is;}
template<class T, class U> bool chmax(T &a, const U &b){return a<b?a=b,1:0;}
template<class T, class U> bool chmin(T &a, const U &b){return a>b?a=b,1:0;}
template <class T> void psum(T& c) {partial_sum(begin(c), end(c), begin(c));}
template<class T> using heap = priority_queue<T, deque<T>, greater<T>>;
struct before_main_function {
  before_main_function() {
      cin.tie(nullptr); ios::sync_with_stdio(0);
      cout << setprecision(15) << fixed;
  }
} before_main_function;
// clang-format on
//------------------8<------------------------------------8<--------------------

struct Edge {
  int to;
  int color;
  int weight;
};
struct UnionFind {
  vector<int> data;
  int comp;
  UnionFind(int size) : data(size, -1), comp(size) {}
  void unite(int x, int y) {
    x = root(x);
    y = root(y);
    if (x != y) {
      if (data[y] < data[x]) swap(x, y);
      data[x] += data[y];
      data[y] = x;
      comp--;
    }
  }
  bool same(int x, int y) { return root(x) == root(y); }
  int root(int x) { return data[x] < 0 ? x : (data[x] = root(data[x])); }
  int size(int x) { return -data[root(x)]; }
  int components() { return comp; }
};
struct LCA {
  using Query = pii;

  vector<vector<Edge>> g;
  vector<int> color;
  vector<int> ancestor;
  vector<vector<pair<int, Query>>> query_set;
  UnionFind uf;
  vector<int> res;

  LCA(const vector<vector<Edge>> &g, vector<Query> &query)
      : g(g),
        color(sz(g)),
        ancestor(sz(g)),
        query_set(sz(g)),
        uf(sz(g)),
        res(sz(query)) {
    int qs = sz(query);
    for (int i = 0; i < qs; ++i) {
      query_set[query[i].first].emplace_back(i, query[i]);
      query_set[query[i].second].emplace_back(i, query[i]);
    }
  }

  void visit(int v, int prev) {
    ancestor[uf.root(v)] = v;
    for (auto &e : g[v]) {
      int w = e.to;
      if (w == prev) {
        continue;
      }
      visit(w, v);
      uf.unite(v, w);
      ancestor[uf.root(v)] = v;
    }
    color[v] = 1;
    for (auto &p : query_set[v]) {
      Query q = p.second;
      int w = (q.second == v ? q.first : (q.first == v ? q.second : -1));
      if (w == -1 || !color[w]) {
        continue;
      }
      res[p.first] = ancestor[uf.root(w)];
    }
  }

  vector<int> solve(int root) {
    visit(root, -1);
    return res;
  }
};

signed main() {
  int N, Q;
  cin >> N >> Q;
  vector<vector<Edge>> G(N);
  rep(i, 0, N - 1) {
    int a, b, c, d;
    cin >> a >> b >> c >> d;
    a--, b--;
    G[a].pb(Edge{b, c, d});
    G[b].pb(Edge{a, c, d});
  }
  vector<pii> lca_queries;
  vector<int> X(Q), Y(Q);
  rep(i, 0, Q) {
    int x, y, u, v;
    cin >> x >> y >> u >> v;
    u--, v--;
    lca_queries.eb(u, v);
    X[i] = x;
    Y[i] = y;
  }
  LCA lca(G, lca_queries);
  auto lca_ans = lca.solve(0);

  struct Ans {
    int num;
    int cost;
  };
  struct EachNode {
    int color;
    Ans &ans;
  };
  struct Query {
    Ans u_ans;
    Ans v_ans;
    Ans l_ans;
  };
  vector<Query> ans(Q);
  vector<vector<EachNode>> qs(N);
  rep(i, 0, Q) {
    int u, v, l;
    u = lca_queries[i].first;
    v = lca_queries[i].second;
    l = lca_ans[i];
    qs[u].pb(EachNode{X[i], ans[i].u_ans});
    qs[v].pb(EachNode{X[i], ans[i].v_ans});
    qs[l].pb(EachNode{X[i], ans[i].l_ans});
  }

  map<int, int> num;
  map<int, int> cost;
  vector<int> cost_sum(N);
  auto dfs = [&](auto f, int v, int p) -> void {
    for (auto &q : qs[v]) {
      int c = q.color;
      q.ans.num = num[c];
      q.ans.cost = cost[c];
    }

    for (auto &e : G[v]) {
      int w = e.to;
      if (w == p) continue;
      num[e.color] += 1;
      cost[e.color] += e.weight;
      cost_sum[w] += cost_sum[v] + e.weight;
      f(f, w, v);
      cost[e.color] -= e.weight;
      num[e.color] -= 1;
    }
  };
  dfs(dfs, 0, -1);

  rep(i, 0, Q) {
    int u, v, l;
    u = lca_queries[i].first;
    v = lca_queries[i].second;
    l = lca_ans[i];

    int a = 0;
    a += cost_sum[u] - cost_sum[l];
    a += cost_sum[v] - cost_sum[l];
    a -= ans[i].u_ans.cost - ans[i].l_ans.cost;
    a += (ans[i].u_ans.num - ans[i].l_ans.num) * Y[i];
    a -= ans[i].v_ans.cost - ans[i].l_ans.cost;
    a += (ans[i].v_ans.num - ans[i].l_ans.num) * Y[i];
    cout << a << endl;
  }
  return (0 ^ _ ^ 0);
}



Measured memory_bytes: 67312