// Template
#include <bits/stdc++.h>
#define rep_override(x, y, z, name, ...) name
#define rep2(i, n) for (int i = 0; i < (n); ++i)
#define rep3(i, l, r) for (int i = (l); i < (r); ++i)
#define rep(...) rep_override(__VA_ARGS__, rep3, rep2)(__VA_ARGS__)
#define all(x) (x).begin(), (x).end()
#define sz(x) (int)(x).size()
using namespace std;
using ll = long long;
constexpr int inf = 1001001001;
constexpr ll INF = 3003003003003003003;
template <typename T> inline bool chmin(T& x, const T& y) {if (x > y) {x = y; return 1;} return 0;}
template <typename T> inline bool chmax(T& x, const T& y) {if (x < y) {x = y; return 1;} return 0;}
struct IOSET {IOSET() {cin.tie(0); ios::sync_with_stdio(0); cout << fixed << setprecision(10);}} ioset;

// Segment Tree
template <typename Operator>
struct SegmentTree {
    Operator OP;
    using NodeType = decltype(OP.NodeE);
    int length;
    vector<NodeType> node;
    SegmentTree (int N) {
        length = 1;
        while (length < N) length <<= 1;
        node.assign(length << 1, OP.NodeE);
    }
    SegmentTree (vector<NodeType> &vec) {
        length = 1;
        while (length < sz(vec)) length <<= 1;
        node.assign(2 * length, OP.NodeE);
        rep(i, sz(vec)) node[i + length] = vec[i];
        for (int i = length - 1; i > 0; --i) node[i] = OP.func(node[(i << 1) + 0], node[(i << 1) + 1]);
    }
    void update(int idx, NodeType val) {
        idx += length;
        node[idx] = OP.change(node[idx], val);
        while (idx >>= 1) node[idx] = OP.func(node[(idx << 1) + 0], node[(idx << 1) + 1]);
    }
    NodeType get(int l, int r) {
        l += length;
        r += length;
        NodeType vl = OP.NodeE, vr = OP.NodeE;
        while (r > l) {
            if (l & 1) vl = OP.func(vl, node[l++]);
            if (r & 1) vr = OP.func(node[--r], vr);
            l >>= 1;
            r >>= 1;
        }
        return OP.func(vl, vr);
    }
};
struct RmQ {
    using NodeType = pair<int, int>;
    NodeType NodeE = pair<int, int>(inf, inf);
    NodeType change(NodeType x, NodeType y) {return y;}
    NodeType func(NodeType x, NodeType y) {return min(x, y);}
};

// Main
struct edge {int to, color, length;};

int main() {
    int n, q;
    cin >> n >> q;
    vector<vector<edge>> g(n);
    rep(i, n - 1) {
        int a, b, c, d;
        cin >> a >> b >> c >> d;
        --a; --b;
        g[a].push_back(edge{b, c, d}); g[b].push_back(edge{a, c, d});
    }
    
    vector<int> id(n, 0), par(n, -1), edges(2 * n), deaphs(2 * n), ls(2 * n);
    vector<vector<int>> inds(n), cnts(n), lengths(n);
    int t = 0;
    auto dfs = [&](auto f, int v, int p, int d) -> void {
        for (edge e: g[v]) {
            if (e.to == p) continue;
            ++t; par[e.to] = v; id[e.to] = t; edges[t] = e.to; deaphs[t] = d + 1; ls[t] = e.length; inds[e.color].push_back(t); cnts[e.color].push_back(1); lengths[e.color].push_back(e.length);
            f(f, e.to, v, d + 1);
            ++t; edges[t] = -e.to; deaphs[t] = d; ls[t] = -e.length; inds[e.color].push_back(t); cnts[e.color].push_back(-1); lengths[e.color].push_back(-e.length);
        }
    };
    edges[0] = 0; deaphs[0] = 0; ls[0] = 0;
    dfs(dfs, 0, -1, 0);
    edges[2 * n - 1] = 0; deaphs[2 * n - 1] = -1; ls[2 * n - 1] = 0;
    
    vector<int> ls_sum(2 * n + 1);
    rep(i, 2 * n) ls_sum[i + 1] = ls_sum[i] + ls[i];
    vector<vector<int>> cnts_sum(n), lengths_sum(n);
    rep(i, n) {
        cnts_sum[i].assign(sz(cnts[i]) + 1, 0); lengths_sum[i].resize(sz(lengths[i]) + 1, 0);
        rep(j, sz(cnts[i])) cnts_sum[i][j + 1] = cnts_sum[i][j] + cnts[i][j];
        rep(j, sz(lengths[i])) lengths_sum[i][j + 1] = lengths_sum[i][j] + lengths[i][j];
    }
    SegmentTree<RmQ> st(2 * n);
    rep(i, 2 * n) st.update(i, pair<int, int>(deaphs[i], edges[i]));
    
    auto sum1 = [&](int x, int y) -> int {
        if (id[x] > id[y]) swap(x, y);
        return ls_sum[id[y] + 1] - ls_sum[id[x] + 1];
    };
    auto sum2 = [&](int c, int x, int y) -> int {
        if (id[x] > id[y]) swap(x, y);
        int x_ = lower_bound(all(inds[c]), id[x] + 1) - inds[c].begin();
        int y_ = lower_bound(all(inds[c]), id[y] + 1) - inds[c].begin();
        return lengths_sum[c][y_] - lengths_sum[c][x_];
    };
    auto sum3 = [&](int c, int x, int y) -> int {
        if (id[x] > id[y]) swap(x, y);
        int x_ = lower_bound(all(inds[c]), id[x] + 1) - inds[c].begin();
        int y_ = lower_bound(all(inds[c]), id[y] + 1) - inds[c].begin();
        return cnts_sum[c][y_] - cnts_sum[c][x_];
    };
    
    rep(i, q) {
        int x, y, u, v;
        cin >> x >> y >> u >> v;
        --u; --v;
        if (id[u] > id[v]) swap(u, v);
        auto p = st.get(id[u], id[v] + 1);
        int lca = p.second;
        if (lca < 0) lca = par[-lca];
        int ans = sum1(lca, u) + sum1(lca, v);
        ans -= (sum2(x, lca, u) + sum2(x, lca, v));
        ans += (sum3(x, lca, u) + sum3(x, lca, v)) * y;
        cout << ans << "\n";
    }
    return 0;
}


Measured memory_bytes: 53376