#include "bits/stdc++.h"
#define _overload3(_1,_2,_3,name,...) name
#define _rep(i,n) repi(i,0,n)
#define repi(i,a,b) for(int i=int(a),i##_len=(b);i<i##_len;++i)
#define MSVC_UNKO(x) x
#define rep(...) MSVC_UNKO(_overload3(__VA_ARGS__,repi,_rep,_rep)(__VA_ARGS__))
#define all(c) c.begin(),c.end()
#define mp make_pair
#define write(x) cout<<(x)<<"\n"
using namespace std; typedef long long ll; typedef vector<int> vi; typedef vector<ll> vll;
template<class T>using vv = vector<vector<T>>; template<class T>auto vvec(int n, int m, T v) { return vv<T>(n, vector<T>(m, v)); }
template<class T>bool chmax(T& a, const T& b) { return a < b ? a = b, 1 : 0; }
template<class T>bool chmin(T& a, const T& b) { return b < a ? a = b, 1 : 0; }
constexpr int INF = 1 << 29, MOD = int(1e9) + 7; constexpr ll LINF = 1LL << 60;
struct aaa { aaa() { cin.tie(0); ios::sync_with_stdio(0); cout << fixed << setprecision(10); }; }aaaa;

template<typename T = int>
struct min_of {
    static const T identity;
    constexpr T operator ()(T& lhs, T& rhs) const { return min<T>(lhs, rhs); }
};
template<typename T> const T min_of<T>::identity = pair<int, int>(INT32_MAX, -1);
template<typename T, class F, const T& I>
struct SegmentTree {
    const F op = F();
    int n; vector<T> dat;
    void init(int n_) { n = 1; while (n < n_) n *= 2; dat.assign(n * 2, I); }
    void build(const vector<T>& v) {
        int n_ = v.size(); init(n_);
        for (int i = 0; i < n_; i++) dat[n + i] = v[i]; for (int i = n - 1; i; i--) dat[i] = op(dat[i << 1], dat[(i << 1) + 1]);
    }
    void update(int k, T x) { dat[k += n] = x; while (k >>= 1) dat[k] = op(dat[k << 1], dat[(k << 1) + 1]); }
    T query(int a, int b) {
        T vl = I, vr = I;
        for (int l = a + n, r = b + n; l < r; l >>= 1, r >>= 1) { if (l & 1) vl = op(vl, dat[l++]); if (r & 1) vr = op(dat[--r], vr); }
        return op(vl, vr);
    }
    template<class C> int find(int a, int b, C& check) { return find(a, b, check, 1, 0, n); }
private:
    template<class C> int find(int a, int b, C& check, int k, int l, int r) {
        if (!check(dat[k]) || r <= a || b <= l) return -1; if (k >= n) return k - n;
        int m = (l + r) >> 1; int vl = find(a, b, check, (k << 1) | 0, l, m);
        if (~vl) return vl; return find(a, b, check, (k << 1) | 1, m, r);
    }
};

int N, Q;
vv<pair<pair<int, int>, int>> graph; // <<cost, color>, to>
vector<int> X, Y, U, V, W;

vector<int> depth;
vector<int> id;
vector<pair<int, int>> depth_vs;
SegmentTree <pair<int, int>, min_of<pair<int, int>>, min_of<pair<int, int>>::identity> depth_min;

vv<int> query;
vector<pair<int, int>> colorInfo;
vector<pair<int, int>> queryAns;

void dfs_lca(int v, int p, int d) {
    depth[v] = d;
    id[v] = depth_vs.size();
    depth_vs.emplace_back(d, v);

    for (auto& w : graph[v]) {
        if (w.second != p) {
            dfs_lca(w.second, v, d + w.first.first);
            depth_vs.emplace_back(d, v);
        }
    }
}

int lca(int u, int v) {
    int s = id[u], t = id[v];
    if (s > t) swap(s, t);
    auto ret = depth_min.query(s, t + 1);
    return ret.second;
}

void dfs(int v, int p) {
    for (int q : query[v]) {
        // クエリの端点が同じ頂点になることはない
        if (q < Q) {
            if (U[q] == v || V[q] == v) {
                queryAns[q].first += colorInfo[X[q]].first;
                queryAns[q].second += colorInfo[X[q]].second;
            }
        }
        else {
            q -= Q;
            if (W[q] == v) {
                queryAns[q].first -= 2 * colorInfo[X[q]].first;
                queryAns[q].second -= 2 * colorInfo[X[q]].second;
            }
        }
    }

    for (auto& w : graph[v]) {
        if (w.second != p) {
            colorInfo[w.first.second].first += w.first.first;
            colorInfo[w.first.second].second++;
            dfs(w.second, v);
            colorInfo[w.first.second].first -= w.first.first;
            colorInfo[w.first.second].second--;
        }
    }
}

int main() {
    cin >> N >> Q;
    graph.resize(N);

    rep(i, N - 1) {
        int a, b, c, d;
        cin >> a >> b >> c >> d;
        a--; b--; c--;
        graph[a].emplace_back(mp(d, c), b);
        graph[b].emplace_back(mp(d, c), a);
    }

    // 普通にLCA求めておく
    depth.resize(N);
    id.resize(N);
    depth_vs.reserve(2 * N);

    dfs_lca(0, -1, 0);
    depth_min.build(depth_vs);

    X.resize(Q); Y.resize(Q); U.resize(Q); V.resize(Q);
    W.resize(Q);
    query.resize(N);

    rep(i, Q) {
        cin >> X[i] >> Y[i] >> U[i] >> V[i];
        X[i]--; U[i]--; V[i]--;
        
        W[i] = lca(U[i], V[i]);

        // if (W[i] < 0 || W[i] >= N) {
        //     return 0;
        // }

        // クエリを頂点に登録 クエリ番号から問題となる端点かLCAかなど判別
        query[U[i]].push_back(i);
        query[V[i]].push_back(i);
        query[W[i]].push_back(Q + i);
    }

    colorInfo.resize(N - 1, mp(0, 0));
    queryAns.resize(Q, mp(0, 0));
    
    dfs(0, -1);

    // 求める値:
    // 普通の距離 - 色の距離origの総和 + 色の距離 * 色の辺の個数
    rep(i, Q) {
        ll ans = depth[U[i]] + depth[V[i]] - 2 * depth[W[i]];
        ans += -queryAns[i].first + Y[i] * queryAns[i].second;

        write(ans);
    }
}

Measured memory_bytes: 26492