#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cassert>
#include <algorithm>
#include <functional>
#include <iostream>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <vector>
#define repi(i,a,b) for(ll i=(a);i<(b);++i)
#define rep(i,a) repi(i,0,a)
#define repdi(i,a,b) for(ll i=(a)-1;i>=(b);--i)
#define repd(i,a) repdi(i,a,0)
#define itr(it,a) for( auto it = (a).begin(); it != (a).end(); ++it )
#define all(a) (a).begin(), (a).end()
#define rall(a) (a).rbegin(), (a).rend()
#define endl '\n'
#define debug(x) std::cerr << #x << " = " << (x) << endl;

using ll = long long;
using P = std::pair<ll, ll>;

constexpr ll INF = 1ll<<60;

template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return 1; } return 0; }
template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return 1; } return 0; }

template<class S, class T>
std::ostream& operator<< ( std::ostream& out, const std::pair<S,T>& a )
{ std::cout << '(' << a.first << ", " << a.second << ')'; return out; }

template<class T>
std::ostream &operator<< ( std::ostream& out, const std::vector<T>& a )
{ std::cout << '['; rep( i, a.size() ){ std::cout << a[i]; if( i != a.size()-1 ) std::cout << ", "; } std::cout << ']'; return out; }

template<typename T> // T: type of cost
struct lca {
  int n, root, l;
  std::vector<std::vector<int>> to;
  std::vector<std::vector<T>> co;
  std::vector<int> dep;
  std::vector<T> costs;
  std::vector<std::vector<int>> par;
  lca(int n):n(n),to(n),co(n),dep(n),costs(n) {
    l = 0;
    while ((1<<l) < n) ++l;
    par = std::vector<std::vector<int>>(n+1,std::vector<int>(l,n));
  }
  void addEdge(int a, int b, T c=0) {
    to[a].push_back(b); co[a].push_back(c);
    to[b].push_back(a); co[b].push_back(c);
  }
  void dfs(int v, int d=0, T c=0, int p=-1) {
    if (p != -1) par[v][0] = p;
    dep[v] = d;
    costs[v] = c;
    for (int i = 0; i < to[v].size(); ++i) {
      int u = to[v][i];
      if (u == p) continue;
      dfs(u, d+1, c+co[v][i], v);
    }
  }

  void init(int _root=0) {
    root = _root;
    dfs(root);
    for (int i = 0; i < l-1; ++i) {
      for (int v = 0; v < n; ++v) {
        par[v][i+1] = par[par[v][i]][i];
      }
    }
  }
  // LCA
  int operator()(int a, int b) {
    if (dep[a] > dep[b]) std::swap(a,b);
    int gap = dep[b]-dep[a];
    for (int i = l-1; i >= 0; --i) {
      int len = 1<<i;
      if (gap >= len) {
        gap -= len;
        b = par[b][i];
      }
    }
    if (a == b) return a;
    for (int i = l-1; i >= 0; --i) {
      int na = par[a][i];
      int nb = par[b][i];
      if (na != nb) a = na, b = nb;
    }
    return par[a][0];
  }
  int length(int a, int b) {
    int c = (*this)(a,b);
    return dep[a]+dep[b]-dep[c]*2;
  }
  T dist(int a, int b) {
    int c = (*this)(a,b);
    return costs[a]+costs[b]-costs[c]*2;
  }
};

struct edge {
  ll to, col, cost;
};

struct query {
  ll qid, col, cost, coef;
};

ll N, Q;
std::vector<edge> G[100010];
std::vector<query> qs[100010];
ll cnt[100010], sum[100010];

ll ans[100010];

void dfs( ll v, ll p = -1 ) {
  for( auto q : qs[v] ) {
    ans[q.qid] -= q.coef*sum[q.col];
    ans[q.qid] += q.coef*cnt[q.col]*q.cost;
  }

  for( auto u : G[v] ) if( u.to != p ) {
    ++cnt[u.col]; sum[u.col] += u.cost;
    dfs( u.to, v );
    --cnt[u.col]; sum[u.col] -= u.cost;
  }
}

int main() {
  std::cin >> N >> Q;

  lca<ll> lc(N+10);

  rep( i, N-1 ) {
    ll a, b, c, d;
    std::cin >> a >> b >> c >> d;
    --a; --b;

    G[a].emplace_back( edge{ b, c, d } );
    G[b].emplace_back( edge{ a, c, d } );
    lc.addEdge( a, b, d );
  }

  lc.init();

  rep( q, Q ) {
    ll x, y, u, v;
    std::cin >> x >> y >> u >> v;

    --u; --v;

    ll w = lc(u,v);

    qs[u].emplace_back( query{ q, x, y, 1 } );
    qs[v].emplace_back( query{ q, x, y, 1 } );
    qs[w].emplace_back( query{ q, x, y, -2 } );

    ans[q] = lc.dist(u,v);
  }

  dfs( 0 );

  rep( q, Q )
    std::cout << ans[q] << endl;

  return 0;
}

Measured memory_bytes: 57404