#include "bits/stdc++.h"
using namespace std;
using ll     = long long;
using pii    = pair<int, int>;
using pll    = pair<ll, ll>;
using vi     = vector<int>;
using vl     = vector<ll>;
using vvi    = vector<vi>;
using vvl    = vector<vl>;
const ll INF = 1LL << 60;
const ll MOD = 1000000007;
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;
}
template <class C>
void print(const C &c, std::ostream &os = std::cout) {
    std::copy(std::begin(c), std::end(c), std::ostream_iterator<typename C::value_type>(os, " "));
    os << std::endl;
}

// 0-indexed bottom up Segment Tree
// UNIT is the identity element of operation func
template <typename T = int>
struct SegmentTree {
    using F = function<T(T, T)>;
    int n;
    vector<T> dat;
    F func;
    T UNIT;

    SegmentTree(int n_, F func_, T UNIT_) : func(func_), UNIT(UNIT_) {
        n = 1;
        // full binary tree: num of leaves = n = 2^k >= n_
        while (n < n_)
            n *= 2;
        dat.assign(2 * n - 1, UNIT);
    }
    SegmentTree(vector<T> v_, F func_, T UNIT_) : func(func_), UNIT(UNIT_) {
        n = 1;
        while (n < v_.size())
            n *= 2;
        dat.assign(2 * n - 1, UNIT);
        for (int i = 0; i < v_.size(); ++i) {
            dat[n - 1 + i] = v_[i];
        }
        for (int i = n - 2; i >= 0; --i) {
            dat[i] = func(dat[2 * i + 1], dat[2 * i + 2]);
        }
    }
    void update(int k, T a) {
        // leaves are at index n-1 to 2*n-2
        k += n - 1;
        dat[k] = a;
        while (k > 0) {
            // k -> parent node
            k = (k - 1) / 2;
            // func(child nodes)
            dat[k] = func(dat[2 * k + 1], dat[2 * k + 2]);
        }
    }
    // get result of func() in [l, r)
    T query(int l, int r) {
        l += n - 1;
        r += n - 1;
        T ret = UNIT;
        while (l < r) {
            if ((l & 1) == 0)
                ret = func(ret, dat[l]);
            if ((r & 1) == 0)
                ret = func(ret, dat[r - 1]);
            l = l / 2;
            r = (r - 1) / 2;
        }
        return ret;
    }
};

// get LCA on the tree
// constructor: n = size of the graph
// addEdge:
// build: after adding all edge, build Euler tour and seg tree
struct LCA {
    int n;
    int k;
    vector<int> depth;
    vector<int> eulerTour;
    vector<int> firstVisit;
    vector<vector<int>> edges;
    SegmentTree<pair<int, int>> segTree;
    static pair<int, int> pairComp(pair<int, int> a, pair<int, int> b) {
        if (a.first < b.first)
            return a;
        else
            return b;
    }
    LCA(int n)
        : n(n), k(0), depth(2 * n - 1), eulerTour(2 * n - 1), firstVisit(n), edges(n),
          segTree(2 * n, pairComp, make_pair(numeric_limits<int>::max(), 0)){};
    void addEdge(int from, int to) {
        edges[from].push_back(to);
        edges[to].push_back(from);
    }
    void dfs(int curr = 0, int par = -1, int d = 0) {
        firstVisit[curr] = k;
        eulerTour[k]     = curr;
        depth[k++]       = d;
        for (auto &e : edges[curr]) {
            if (e != par) {
                dfs(e, curr, d + 1);
                eulerTour[k] = curr;
                depth[k++]   = d;
            }
        }
    }
    void build(int root = 0) {
        dfs(root);
        for (int i = 0; i < 2 * n - 1; ++i) {
            segTree.update(i, make_pair(depth[i], eulerTour[i]));
        }
    }
    // return LCA node of l and r
    int operator()(int l, int r) {
        int left  = firstVisit[l];
        int right = firstVisit[r];
        if (left > right)
            swap(left, right);
        return segTree.query(left, right + 1).second;
    }
    int getDepth(int k) { return depth[firstVisit[k]]; }
};

int main() {
    int n, q;
    cin >> n >> q;
    LCA lca(n);
    vector<vector<pair<int, pii>>> edges(n);
    for (int i = 0; i < n - 1; ++i) {
        int a, b, c, d;
        cin >> a >> b >> c >> d;
        a--, b--;
        lca.addEdge(a, b);
        edges[a].push_back({b, {c, d}});
        edges[b].push_back({a, {c, d}});
    }
    lca.build();
    vl ret(q);
    struct query {
        int i, x, y, sign;
    };
    vector<vector<query>> vq(n);
    for (int i = 0; i < q; ++i) {
        int x, y, u, v;
        cin >> x >> y >> u >> v;
        u--, v--;
        int l = lca(u, v);
        vq[u].push_back({i, x, y, 1});
        vq[v].push_back({i, x, y, 1});
        vq[l].push_back({i, x, y, -2});
    }
    vl len(n, 0), cnt(n, 0);
    ll tot                       = 0;
    function<void(int, int)> dfs = [&](int c, int p) {
        for (auto &q : vq[c]) {
            ll cost = tot - len[q.x] + cnt[q.x] * q.y;
            ret[q.i] += cost * q.sign;
        }
        for (auto &e : edges[c]) {
            if (e.first == p)
                continue;
            tot += e.second.second;
            len[e.second.first] += e.second.second;
            cnt[e.second.first]++;
            dfs(e.first, c);
            tot -= e.second.second;
            len[e.second.first] -= e.second.second;
            cnt[e.second.first]--;
        }
    };
    dfs(0, -1);
    for (int i = 0; i < q; ++i) {
        cout << ret[i] << "\n";
    }
    return 0;
}

Measured memory_bytes: 34292