#include <iostream>
#include <algorithm>
#include <vector>
#include <functional>

template <class Cost = int>
struct Edge {
    int src, dst;
    Cost cost;
    int color;
    int dir;
    Edge(int src = -1, int dst = -1, Cost cost = 1, int color = -1)
        : src(src), dst(dst), cost(cost), color(color), dir(1){};

    bool operator<(const Edge<Cost>& e) const { return this->cost < e.cost; }
    bool operator>(const Edge<Cost>& e) const { return this->cost > e.cost; }
};

template <class Cost = int>
using Edges = std::vector<Edge<Cost>>;

using Graph = std::vector<std::vector<int>>;

template <class T>
struct SegmentTree {
    using Merger = std::function<T(T, T)>;

    int length;
    std::vector<T> dat;
    T unit;
    Merger merge;

    explicit SegmentTree(int n, T unit, Merger merge)
        : length(1), unit(unit), merge(merge) {
        while (length < n) length <<= 1;
        dat.assign(length * 2, unit);
    }

    T query(int ql, int qr) {
        ql = std::max(ql, 0);
        qr = std::min(qr, length);
        ql += length, qr += length;

        T lacc = unit, racc = unit;
        while (ql < qr) {
            if (ql & 1) {
                lacc = merge(lacc, dat[ql]);
                ++ql;
            }
            if (qr & 1) {
                --qr;
                racc = merge(dat[qr], racc);
            }
            ql >>= 1, qr >>= 1;
        }
        return merge(lacc, racc);
    }

    void update(int nidx, T elem) {
        nidx += length;
        dat[nidx] = elem;

        while (nidx > 0) {
            nidx >>= 1;
            T vl = dat[nidx * 2 + 0];
            T vr = dat[nidx * 2 + 1];
            dat[nidx] = merge(vl, vr);
        }
    }
};

struct Query {
    int c, d, u, v, id;
    Query(int c, int d, int u, int v, int id)
        : c(c), d(d), u(u), v(v), id(id) {}
};

void solve() {
    int n, q;
    std::cin >> n >> q;
    int m = (n - 1) * 2;

    Edges<int> edges;
    edges.reserve(m);
    Graph graph(n);
    std::vector<std::vector<int>> ces(n - 1);

    for (int i = 0; i < n - 1; ++i) {
        int u, v, c, d;
        std::cin >> u >> v >> c >> d;
        --u, --v, --c;

        graph[u].push_back(edges.size());
        ces[c].push_back(edges.size());
        edges.emplace_back(u, v, d, c);

        graph[v].push_back(edges.size());
        ces[c].push_back(edges.size());
        edges.emplace_back(v, u, d, c);
    }

    std::vector<std::vector<Query>> queries(n - 1);
    for (int i = 0; i < q; ++i) {
        int c, d, u, v;
        std::cin >> c >> d >> u >> v;
        --c, --u, --v;
        queries[c].emplace_back(c, d, u, v, i);
    }

    std::vector<int> depth(n), ein(m), vs(m + 1), vin(n);
    {
        int time = 0;
        std::function<void(int, int)> dfs =
            [&](int v, int p) {
                vs[time] = v;
                vin[v] = time;
                for (auto ei : graph[v]) {
                    auto& u = edges[ei].dst;
                    if (u == p) continue;

                    depth[u] = depth[v] + 1;
                    ein[ei] = time++;

                    dfs(u, v);

                    ein[ei ^ 1] = time++;
                    vs[time] = v;
                    edges[ei ^ 1].dir = -1;
                }
            };

        int r = 0;
        depth[r] = 0;
        dfs(r, -1);
    }

    SegmentTree<std::pair<int, int>>
        dseg(m, std::make_pair(n, -1),
             [&](auto a, auto b) { return std::min(a, b); });

    for (int i = 0; i < m; ++i) {
        dseg.update(i, std::make_pair(depth[vs[i]], vs[i]));
    }

    SegmentTree<int>
        oseg(m, 0, [&](auto a, auto b) { return a + b; });
    auto eseg = oseg, cseg = oseg;

    for (int ei = 0; ei < m; ++ei) {
        const auto& e = edges[ei];
        oseg.update(ein[ei], e.cost * e.dir);
    }

    std::vector<int> anss(q);
    for (int c = 0; c < n - 1; ++c) {
        for (auto ei : ces[c]) {
            const auto& e = edges[ei];
            eseg.update(ein[ei], e.cost * e.dir);
            cseg.update(ein[ei], e.dir);
        }

        for (auto qq : queries[c]) {
            auto query = [&](int v) {
                return oseg.query(0, v) - eseg.query(0, v) +
                       cseg.query(0, v) * qq.d;
            };

            auto& ans = anss[qq.id];
            if (vin[qq.u] > vin[qq.v]) std::swap(qq.u, qq.v);

            int w = dseg.query(vin[qq.u], vin[qq.v] + 1).second;
            ans = query(vin[qq.u]) + query(vin[qq.v]) -
                  query(vin[w]) * 2;
        }

        for (auto ei : ces[c]) {
            eseg.update(ein[ei], 0);
            cseg.update(ein[ei], 0);
        }
    }

    for (auto ans : anss) std::cout << ans << std::endl;
}

int main() {
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
    std::ios::sync_with_stdio(false);

    solve();

    return 0;
}


Measured memory_bytes: 38704