#include <bits/stdc++.h>
using namespace std;
using ll = long long;

// Euler tour など, 蟻本p.292-297
// https://atcoder.jp/contests/abc133/tasks/abc133_f

#define MAX_V 100001 // 1-indexed

// RMQ を求めるセグ木, 完全二分木, 蟻本p.155
// 最小値のindexが欲しいのでpairにしてsecondに持たせる
struct segTree{
    int size; // 2べき, 葉の数
    vector<pair<int, int>> cbt; // complete binary tree
    // cbt[size*2-1] はINT_MAXで固定

    // INT_MAX で初期化
    segTree(int N){
        size = 1;
        while (size < N){
            size *= 2;
        }
        cbt.resize(size * 2, {INT_MAX, size*2-1});
    }

    // v.size <= size の vector を入力, O(N)
    void input(vector<int> v){
        for (int i = 0; i < v.size(); ++i) {
            cbt[size+i-1] = {v[i], i};
        }
        for (int i = size - 2; i >= 0; --i) {
            cbt[i] = min(cbt[i*2+1], cbt[i*2+2]);
        }
    }

    // 葉のi番目(0-indexed)をxに更新
    void update(int i, int x){
        i += size - 1;
        cbt[i] = {x, i};
        while (i > 0){
            i = (i - 1) / 2;
            cbt[i] = min(cbt[i*2+1], cbt[i*2+2]);
        }
    }

    // 区間[a, b) (0-indexed)の最小値を返す関数
    // 外から呼ぶときは query(a, b, 0, 0, *.size)
    pair<int, int> query(int a, int b, int k, int l, int r){
        if(r <= a || b <= l) return {INT_MAX, size*2-1};
        if(a <= l && r <= b) return cbt[k];
        pair<int, int> vl = query(a, b, k*2+1, l, (l+r)/2);
        pair<int, int> vr = query(a, b, k*2+2, (l+r)/2, r);
        return min(vl, vr);
    }
};

struct edge{int to, cost, color;};
vector<edge> graph[MAX_V];

// Euler tour
// depth を RMQ に投げれば LCA が求まる
int vs[MAX_V*2]; // 頂点の訪問順
vector<int> depth(MAX_V*2, INT_MAX); // ↑の頂点の根からの深さ
int ls[MAX_V]; // 頂点iを最初に訪問するindex
int rs[MAX_V]; // 頂点iを最後に訪問するindex
pair<edge, int> es[MAX_V*2]; // 辺の訪問順
int dist[MAX_V]; // 根を1として根からの距離
void dfs(int v, int par, int d, int &idx){
    ls[v] = idx;
    vs[idx] = v;
    depth[idx] = d;
    idx++;
    for (edge u: graph[v]) {
        if(u.to == par) continue;
        dist[u.to] = dist[v] + u.cost;
        es[idx-1] = {u, 1};
        dfs(u.to, v, d+1, idx);
        es[idx-1] = {u, -1};
        vs[idx] = v;
        depth[idx] = d;
        idx++;
    }
    rs[v] = idx - 1;
}

segTree tree(MAX_V*2);
void init(){
    dist[1] = 0;
    int idx = 0;
    depth[1] = 0;
    dfs(1, -1, 0, idx);
    tree.input(depth);
}

int LCA(int u, int v){
    return tree.query(min(ls[u], ls[v]), max(ls[u], ls[v]), 0, 0, tree.size).second;
}

int main() {
    int N, Q;
    cin >> N >> Q;
    vector<int>a(N-1);
    vector<int>b(N-1);
    vector<int>c(N-1);
    vector<int>d(N-1);
    for (int i = 0; i < N - 1; ++i) {
        cin >> a[i] >> b[i] >> c[i] >> d[i];
    }
    vector<int>x(Q);
    vector<int>y(Q);
    vector<int>u(Q);
    vector<int>v(Q);
    for (int i = 0; i < Q; ++i) {
        cin >> x[i] >> y[i] >> u[i] >> v[i];
    }

    for (int i = 0; i < N - 1; ++i) {
        graph[a[i]].push_back((edge){b[i], d[i], c[i]});
        graph[b[i]].push_back((edge){a[i], d[i], c[i]});
    }
    init();

    // 各色ごとに累積和
    vector<vector<int>> index(N, vector<int>());
    vector<vector<int>> cost(N, vector<int>());
    vector<vector<int>> num(N, vector<int>());
    for (int i = ls[1]; i < rs[1]; ++i) {
        int color = es[i].first.color;
        index[color].push_back(i);
        cost[color].push_back(es[i].first.cost * es[i].second);
        num[color].push_back(es[i].second);
        int size = index[color].size();
        if(size == 1) continue;
        cost[color][size-1] += cost[color][size-2];
        num[color][size-1] += num[color][size-2];
    }

    for (int i = 0; i < Q; ++i) {
        int lca = LCA(u[i], v[i]);
        int ans = dist[u[i]] + dist[v[i]] - dist[vs[lca]] * 2;
        // color = x[i] の重みをを y[i]に変更
        // esのls[]未満の辺のcost, num
        int u_cost, u_num, v_cost, v_num, lca_cost, lca_num;
        auto iter1 = upper_bound(index[x[i]].begin(), index[x[i]].end(), ls[u[i]] - 1);
        int index1 = iter1 - index[x[i]].begin() - 1;
        if(index1 == -1) {
            u_cost = 0;
            u_num = 0;
        } else{
            u_cost = cost[x[i]][index1];
            u_num = num[x[i]][index1];
        }
        auto iter2 = upper_bound(index[x[i]].begin(), index[x[i]].end(), ls[v[i]] - 1);
        int index2 = iter2 - index[x[i]].begin() - 1;
        if(index2 == -1) {
            v_cost = 0;
            v_num = 0;
        } else{
            v_cost = cost[x[i]][index2];
            v_num = num[x[i]][index2];
        }
        auto iter3 = upper_bound(index[x[i]].begin(), index[x[i]].end(), ls[vs[lca]] - 1);
        int index3 = iter3 - index[x[i]].begin() - 1;
        if(index3 == -1) {
            lca_cost = 0;
            lca_num = 0;
        } else{
            lca_cost = cost[x[i]][index3];
            lca_num = num[x[i]][index3];
        }
        ans = ans + (v_num + u_num - lca_num * 2) * y[i] - (v_cost + u_cost - lca_cost * 2);
        cout << ans << "\n";
    }
    return 0;
}

Measured memory_bytes: 38256