#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace std;
template<typename T, typename V = __gnu_pbds::null_type>
using ordered_set = __gnu_pbds::tree<T, V, less<T>, __gnu_pbds::rb_tree_tag, __gnu_pbds::tree_order_statistics_node_update>;
// find_by_order(), order_of_key()
#define SZ(v) int((v).size())
#define ALL(vec) (vec).begin(),(vec).end()
typedef long long i64;
template<typename T> inline bool uax(T &x, T y) {return (y > x) ? x = y, true : false;}
template<typename T> inline bool uin(T &x, T y) {return (y < x) ? x = y, true : false;}
#define error(args...) { string _s = #args; replace(_s.begin(), _s.end(), ',', ' '); \
  stringstream _ss(_s); istream_iterator<string> _it(_ss); err(_it, args); }
void err(istream_iterator<string>) {}
template<typename T1,typename T2> ostream& operator<<(ostream& os, pair<T1,T2> buf) {
  return os << "(" << buf.first << ": " << buf.second << ")"; }
#define DefOut(Con) template<typename T>ostream&operator<<(ostream&os,Con<T>&A){ bool f = false; os << "{"; \
  for (const auto e: A) { if (f) os << ", "; os << e; f = true; } return os << "}"; }
#define DefOut2(Con) template<typename K,typename V>ostream&operator<<(ostream&os,Con<K,V>&A) \
{ bool f = false; os << "{"; for (auto &e: A) { if (f) os << ", "; os << e; f = true; } return os << "}"; }
template<typename T>ostream &operator << (ostream &os,vector<vector<T>>& A) {
  for (auto &B: A) os << '\n' << B; return os; }
DefOut(vector) DefOut(set) DefOut(multiset) DefOut2(map) 
template<typename T,typename... Args> void err(istream_iterator<string> it, T a, Args... args) {
  cerr << *it << " =: " << a << endl; err(++it, args...); }
template<typename T> void kek(T ans) {cout << ans << endl; exit(0);}
int const MOD = 1e9 + 7;
long long const INF = 1e18;
/***********************************************************************/
template<class Monoid>
class LCA {
  using T = typename Monoid::type;
  struct Edge {
    int to;
    T cost;
  };
  bool is_build;
  const int size;
  int log_size, root;
  vector<vector<int>> parent;
  vector<vector<T>> dp;
  vector<int> depth;
  vector<vector<Edge>> G;
  void dfs(int v, int pv) {
    parent[0][v] = pv;
    for (const auto &e: G[v]) {
      if (e.to != pv) {
        depth[e.to] = depth[v]+1;
        dfs(e.to, v);
        dp[0][e.to] = e.cost;
      }
    }
  }

public:
  LCA(const int n, const int _root) : is_build(false), size(n), log_size(0), root(_root), depth(size, 0), G(n) {
    for (int v = size; v > 0; v /= 2) ++log_size;
    ++log_size;
  }
  void add(int a, int b, T c) {
    G[a].push_back({b, c});
    G[b].push_back({a, c});
  }
  void build() {
    is_build = true;
    parent.assign(log_size, vector<int>(size, -1));
    dp.assign(log_size, vector<T>(size, Monoid::id()));
    dfs(root, -1);
    for (int k = 0; k < log_size - 1; ++k) for (int v = 0; v < size; ++v) {
      if (parent[k][v] < 0) {
        parent[k+1][v] = -1;
        dp[k+1][v] = dp[k][v];
      }
      else {
        parent[k+1][v] = parent[k][parent[k][v]];
        dp[k+1][v] = Monoid::op(dp[k][v], dp[k][parent[k][v]]);
      }
    }
  }
  int lca(int u, int v) {
    if (!is_build) build();
    if (depth[u] > depth[v]) std::swap(u, v);
    T res = Monoid::id();
    for (int k = 0; k < log_size; ++k) {
      if (((depth[v] - depth[u]) >> k) & 1) {
        res = Monoid::op(res, dp[k][v]);
        v = parent[k][v];
      }
    }
    if (u == v) return u;
    for (int k = log_size - 1; ~k; --k) {
      if (parent[k][u] != parent[k][v]) {
        res = Monoid::op(res, dp[k][u]);
        res = Monoid::op(res, dp[k][v]);
        u = parent[k][u];
        v = parent[k][v];
      }
    }
    //~ assert(parent[0][u] == parent[0][v]);
    res = Monoid::op(res, dp[0][u]);
    res = Monoid::op(res, dp[0][v]);
    return parent[0][u];
  }
};
struct Sum {
  using type = i64;
  static type id() { return 0; }
  static type op(const type &l, const type &r) { return l + r; }
};
struct qry {
  i64 c, d, i, ad;
};
struct edge {
  i64 v, c, d;
};
int32_t main() {
  ios_base::sync_with_stdio(false);
  cin.tie(nullptr);

  int n, q;
  cin >> n >> q;
  vector<vector<edge>> g(n);
  auto lca = LCA<Sum>(n + 1, 0);
  for (int i = 0; i < n - 1; ++i) {
    i64 u, v, c, d;
    cin >> u >> v >> c >> d;
    --u; --v; --c;
    lca.add(u, v, d);
    g[u].push_back({v, c, d});
    g[v].push_back({u, c, d});
  }
  vector<vector<qry>> b(n);
  vector<i64> ans(q, 0);
  for (int i = 0; i < q; ++i) {
    int x, y, u, v;
    cin >> x >> y >> u >> v;
    --u; --v; --x;
    int lc = lca.lca(u, v);
    b[u].push_back({x, y, i, 1LL});
    b[v].push_back({x, y, i, 1LL});
    b[lc].push_back({x, y, i, -2LL});
  }
  vector<i64> cnt(n - 1, 0), sum(n - 1, 0);
  i64 asum = 0;
  function<void(int,int)> dfs = [&] (int u, int p) {
    for (const auto &t: b[u]) {
      i64 now = asum - sum[t.c] + (cnt[t.c] * t.d);
      ans[t.i] += t.ad * now;
    }
    for (const auto &e: g[u]) if (e.v != p) {
      cnt[e.c]++;
      sum[e.c] += e.d;
      asum += e.d;
      dfs(e.v, u);
      asum -= e.d;
      cnt[e.c]--;
      sum[e.c] -= e.d;
    }
  };
  dfs(0, -1);
  for (i64 z: ans) cout << z << '\n';
  
  return 0;
} 


Measured memory_bytes: 60772