#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <stack>
#include <queue>
#include <cmath>
#include <tuple>
#include <cstdio>
#include <bitset>
#include <sstream>
#include <iterator>
#include <numeric>
#include <map>
#include <cstring>
#include <set>
#include <functional>
#include <iomanip>

using namespace std;

#define DEBUG_ //!!提出時にコメントアウト!!
#ifdef DEBUG_
	#define dump(x)  cerr << #x << " = " << (x) << endl;
#else
	#define dump(x)  ;
#endif

#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define REP(i,n)  FOR(i,0,n)
#define SZ(x) ((int)(x).size())
#define pb push_back
#define eb emplace_back

//#define int long long

typedef long long LL;
typedef vector<int> VI;
typedef vector<LL> VL;
typedef vector<VI> VVI;
typedef vector<string> VS;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;

template <typename T>
std::string printVector(const std::vector<T> &data)
{
    std::stringstream ss;
    std::ostream_iterator<T> out_it(ss, ", ");
    ss << "[";
    std::copy(data.begin(), data.end() - 1, out_it);
    ss << data.back() << "]";
    return ss.str();
}

const int MOD = 1e9+7;
const LL LINF = 1001002003004005006ll;
const int INF = 1001001001;

template< typename T >
struct edge {
  int src, to;
  T cost;
  edge(int to, T cost) : src(-1), to(to), cost(cost) {}
  edge(int src, int to, T cost) : src(src), to(to), cost(cost) {}
  edge &operator=(const int &x) {
    to = x;
    return *this;
  }
  operator int() const { return to; }
};
template< typename T >
using Edges = vector< edge< T > >;
template< typename T >
using WeightedGraph = vector< Edges< T > >;
using UnWeightedGraph = vector< vector< int > >;
template< typename T >
using Matrix = vector< vector< T > >;

template< typename G >
struct DoublingLowestCommonAncestor {
  const int LOG;
  vector< int > dep;
  const G &g;
  vector< vector< int > > table;

  DoublingLowestCommonAncestor(const G &g) : g(g), dep(g.size()), LOG(32 - __builtin_clz(g.size())) {
    table.assign(LOG, vector< int >(g.size(), -1));
  }

  void dfs(int idx, int par, int d) {
    table[0][idx] = par;
    dep[idx] = d;
    for(auto &to : g[idx]) {
      if(to != par) dfs(to, idx, d + 1);
    }
  }

  void build() {
    dfs(0, -1, 0);
    for(int k = 0; k + 1 < LOG; k++) {
      for(int i = 0; i < table[k].size(); i++) {
        if(table[k][i] == -1) table[k + 1][i] = -1;
        else table[k + 1][i] = table[k][table[k][i]];
      }
    }
  }

  int query(int u, int v) {
    if(dep[u] > dep[v]) swap(u, v);
    for(int i = LOG - 1; i >= 0; i--) {
      if(((dep[v] - dep[u]) >> i) & 1) v = table[i][v];
    }
    if(u == v) return u;
    for(int i = LOG - 1; i >= 0; i--) {
      if(table[i][u] != table[i][v]) {
        u = table[i][u];
        v = table[i][v];
      }
    }
    return table[0][u];
  }
};

vector<VI> edges1[112345];
VI need[112345]; //頂点iについて値が必要になる色たち
map<int,int> res_num[112345], res_sum[112345]; //頂点iから根までの色cの辺の本数, およびその長さの合計
int now_num[112345], now_sum[112345]; //今見ている頂点から根までの色cの辺の本数,およびその長さの合計
int depth[112345] = {}; //根との距離

void dfs(int idx, int par, int dist){
    depth[idx] = dist;
    for(auto c : edges1[idx]){
        //if(c.first != par) dfs(c.first, idx, c.second + dist);
        if(c[0] != par) dfs(c[0], idx, c[2] + dist);
    }
}

void dfs2(int i, int p){
    for(int c : need[i]){
        res_num[i][c] = now_num[c];
        res_sum[i][c] = now_sum[c];
    }
    for(auto e : edges1[i]){
        int j = e[0], c = e[1], d = e[2];
        if(j == p) continue;

        now_num[c]++;
        now_sum[c] += d;
        dfs2(j,i);
        now_num[c]--;
        now_sum[c] -= d;
    }
}

signed main(int argc, char const *argv[])
{
    cin.tie(0);
    ios::sync_with_stdio(false);
    int N,Q; cin >> N >> Q;
    UnWeightedGraph g(N);
    REP(i,N-1){
        int a,b,c,d; cin >> a >> b >> c >> d;
        a--; b--; c--;
        g[a].eb(b);
        g[b].eb(a);
        edges1[a].pb({b,c,d});
        edges1[b].pb({a,c,d});
    }
    DoublingLowestCommonAncestor<UnWeightedGraph> lca(g);
    lca.build();
    dfs(0,-1,0);

    int X[112345], Y[112345], U[112345], V[112345], L[112345];
    REP(i,Q){
        cin >> X[i] >> Y[i] >> U[i]>> V[i];
        X[i]--; U[i]--; V[i]--;
        L[i] = lca.query(U[i],V[i]);
        need[U[i]].eb(X[i]);
        need[V[i]].eb(X[i]);
        need[L[i]].eb(X[i]);
    }

    dfs2(0,-1);

    REP(i,Q){
        int x = X[i], y = Y[i], u = U[i],v = V[i], l = L[i];

        int du = depth[u] - res_sum[u][x] + res_num[u][x] * y;
        int dv = depth[v] - res_sum[v][x] + res_num[v][x] * y;
        int dl = depth[l] - res_sum[l][x] + res_num[l][x] * y;
        int ans = du + dv - 2*dl;
        cout << ans << endl;

    }



}


Measured memory_bytes: 76340