#include <bits/stdc++.h>

using namespace std;

struct Edge {
    int u, v, c;
    long long d;
    Edge() {}
    Edge(int u, int v, int c, long long d): u(u), v(v), c(c), d(d) {}
    friend istream& operator>>(istream& in, Edge& e) {
        in >> e.u >> e.v >> e.c >> e.d;
        --e.u;
        --e.v;
        return in;
    }
    Edge opposite() const {
        return Edge(v, u, c, d);
    }
};

struct Shortcut {
    int node;
    map<int, int> num;
    map<int, long long> dist;
    long long total_dist;
};

Shortcut merge_shortcuts(Shortcut& s0, Shortcut s1) {
    for (auto entry : s0.num) {
        s1.num[entry.first] += entry.second;
    }
    for (auto entry : s0.dist) {
        s1.dist[entry.first] += entry.second;
    }
    s1.total_dist += s0.total_dist;
    return s1;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    long long prime = 1000000007;
    int n, q;
    cin >> n >> q;
    vector<vector<Edge>> adj_list(n);
    for (int i = 0; i < n-1; ++i) {
        Edge edge;
        cin >> edge;
        adj_list[edge.u].push_back(edge);
        adj_list[edge.v].push_back(edge.opposite());
    }
    vector<int> depth(n);
    vector<Edge> parent_edge(n);
    function<void (int, int, int)> root_tree = [&](int i, int p, int d) {
        depth[i] = d;
        if (p == -1) {
            parent_edge[i] = Edge(i, i, 0, 0);
        } else {
            int parent_index = -1;
            for (int j = 0; j < (int) adj_list[i].size(); ++j) {
                if (adj_list[i][j].v == p) {
                    parent_index = j;
                }
            }
            assert(parent_index != -1);
            parent_edge[i] = adj_list[i][parent_index];
            adj_list[i].erase(adj_list[i].begin() + parent_index);
        }
        for (Edge& edge : adj_list[i]) {
            root_tree(edge.v, edge.u, d+1);
        }
    };
    root_tree(0, -1, 0);
    mt19937 rng(chrono::system_clock::now().time_since_epoch().count());
    long long best_price = n*n, best_k = 0;
    for (int t = 0; t < 20; ++t) {
        long long price = 0;
        int k = rng() % n;
        for (int d : depth) {
            price += (k+d) & (-(k+d));
        }
        if (price < best_price) {
            best_price = price;
            best_k = k;
        }
    }
    for (int& d : depth) {
        d += best_k;
    }
    vector<vector<int>> p_shortcut(n);
    vector<vector<Shortcut>> shortcuts(n);
    for (int i = 0; i < n; ++i) {
        Shortcut s;
        s.node = parent_edge[i].v;
        s.num[parent_edge[i].c] = 1;
        s.dist[parent_edge[i].c] = parent_edge[i].d;
        s.total_dist = parent_edge[i].d;
        shortcuts[i].push_back(s);
        p_shortcut[i].push_back(parent_edge[i].v);
    }
    for (int t = 1; t < 20; ++t) {
        for (int i = 0; i < n; ++i) {
            if (i == 0 || depth[i] % (1 << t) == 0) {
                Shortcut& s0 = shortcuts[i][t-1]; // 2^(t-1) up.
                Shortcut& s1 = shortcuts[s0.node][t-1]; //2^(t-1) up.
                shortcuts[i].push_back(merge_shortcuts(s0, s1));
            }
            p_shortcut[i].push_back(p_shortcut[p_shortcut[i][t-1]][t-1]);
        }
    }
    vector<int> lg(n+1, 0);
    for (int i = 2; i <= n; ++i) {
        lg[i] = lg[i/2] + 1;
    }
    auto lca = [&](int u, int v) {
        if (depth[u] < depth[v]) {
            swap(u, v);
        }
        // so depth[u] >= depth(v)
        while (depth[u] > depth[v]) {
            u = p_shortcut[u][lg[depth[u]-depth[v]]];
        }
        assert (depth[u] == depth[v]);
        // now u and v have the same depth
        if (u == v) {
            return u;
        }
        for (int t = 19; t >= 0; --t) {
            int u2 = p_shortcut[u][t], v2 = p_shortcut[v][t];
            if (u2 != v2) {
                u = u2;
                v = v2;
            }
        }
        return p_shortcut[u][0];
    };
    function<long long(int, int, int)> dist_to_root = [&](int u, int x, int y) {
        int num = 0;
        long long color_dist = 0LL;
        long long total_dist = 0LL;
        while (u != 0) {
            Shortcut& s = shortcuts[u].back();
            if (s.num.find(x) != s.num.end()) {
                num += s.num[x];
                color_dist += s.dist[x];
            }
            total_dist += s.total_dist;
            u = s.node;
        }
        return (total_dist - color_dist) + num * y;
    };
    vector<long long> results(q);
    for (int i = 0; i < q; ++i) {
        int x, y, u, v;
        cin >> x >> y >> u >> v;
        --u;
        --v;
        int w = lca(u, v);
        results[i] = dist_to_root(u, x, y) + dist_to_root(v, x, y) - 2*dist_to_root(w, x, y);
    }
    for (auto result : results) {
        cout << result << "\n";
    }
    return 0;
}


Measured memory_bytes: 167424