#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll> P;
typedef pair<ll, P> P3;
typedef pair<P ,P> PP;
constexpr ll MOD = ll(1e9) + 7;
constexpr int IINF = INT_MAX;
constexpr ll LLINF = LLONG_MAX;
constexpr int MAX_N = int(1e5) + 5;
constexpr double EPS = 1e-9;
constexpr int di[] = {0, 1, 0, -1}, dj[] = {1, 0, -1, 0};
#define REP(i, n) for (int i = 0; i < n; i++)
#define REPR(i, n) for (int i = n; i > 0; i--)
#define SORT(v) sort((v).begin(), (v).end())
#define SORTR(v) sort((v).rbegin(), (v).rend())
#define ALL(v) (v).begin(), (v).end()


template <typename Monoid>
struct SegmentTree{
private:
    using F = function<Monoid(Monoid, Monoid)>;
    int N;
    vector<Monoid> node;
    F f;
    Monoid e;  // identity element

public:
    SegmentTree(){}
    SegmentTree(F f, Monoid e):f(f), e(e){}
    void init(int sz){
        N = 1;
        while(N < sz) N <<= 1;
        node.assign(2*N-1, e);
    }
    void build(vector<Monoid>& v){
        int sz = int(v.size());
        init(sz);
        for(int i=0; i<sz; i++){
            node[i+N-1] = v[i];
        }
        for(int i=N-2; i>=0; i--){
            node[i] = f(node[i*2+1], node[i*2+2]);
        }
    }
    void update(int k, Monoid x){
        k += N-1;
        node[k] = x;
        while(k > 0){
            k = (k-1)/2;
            node[k] = f(node[2*k+1], node[2*k+2]);
        }
    }
    // [a,b)
    Monoid query(int a, int b){return query(a, b, 0, 0, N);}
    Monoid query(int a, int b, int k, int l, int r){
        if(b <= l || r <= a) return e;
        if(a <= l && r <= b) return node[k];
        Monoid vl, vr;
        vl = query(a, b, 2*k+1, l, (l+r)/2);
        vr = query(a, b, 2*k+2, (l+r)/2, r);
        return f(vl, vr);
    }
};


struct edge
{
    int from, to, c, d;
};


int n, q, root = 0;
vector<vector<edge> > g, ec;
vector<int> depth, vs, id, idr;

auto funcmin = [=](P a, P b){return min(a,b);};
SegmentTree<P> rmq(funcmin,{IINF, -1});
auto funcsum = [=](int a, int b){return a+b;};
SegmentTree<int> rsq(funcsum, 0);

void dfs(int v, int p, int d, int &k){
    id[v] = k;
    vs[k] = v;
    depth[k] = d;
    k++;
    for(auto e : g[v]){
        if(e.to == p) continue;
        dfs(e.to, v, d+1, k);
        vs[k] = v;
        depth[k] = d;
        k++;
    }
    idr[v] = k;
}

// LCAの前計算
void init(){
    int k=0;
    depth.resize(n*2-1);
    vs.resize(n*2-1);
    id.resize(n);
    idr.resize(n);
    dfs(root,-1,0,k);
    vector<P> tmp;
    for(int i=0;i<k;i++){
        tmp.push_back({depth[i], vs[i]});
    }
    rmq.build(tmp);
    rsq.init(k);
}

// LCAの取得
int LCA(int u, int v){
    return rmq.query(min(id[u], id[v]), max(id[u], id[v])+1).second;
}

// 辺の重みを更新
void update(int v, int w){
    rsq.update(id[v]-1, w);
    rsq.update(idr[v]-1, -w);
}

// 2頂点間の距離を取得
int getDist(int u, int v){
    int w = LCA(u, v);
    return rsq.query(id[root], id[u]) + rsq.query(id[root], id[v]) - rsq.query(id[root],id[w])*2;
}

int main() {
    cin >> n >> q;
    g.resize(n);
    ec.resize(n);
    for(int i=0;i<n-1;i++){
        int a, b, c, d;
        cin >> a >> b >> c >> d;
        a--; b--; c--;
        g[a].push_back({a,b,c,d});
        g[b].push_back({b,a,c,d});
        ec[c].push_back({a,b,c,d});
    }
    init();
    // 元のグラフの重みを構築
    for(int i=0;i<n;i++){
        for(auto e : g[i]){
            if(depth[id[e.to]] < depth[id[i]]){
                update(i, e.d);
            }
        }
    }
    vector<int> ans(q);
    vector<vector<PP> > cq(n);  // 色ごとのクエリ
    for(int i=0;i<q;i++){
        int x, y, u, v;
        cin >> x >> y >> u >> v;
        x--; u--; v--;
        ans[i] = getDist(u, v);  // 元のグラフの距離を求める
        cq[x].push_back({{y,i},{u,v}});
    }
    rsq.init(2*n-1);  // 辺の重みをすべて0にする
    // 色でまとめてクエリに答える
    for(int i=0;i<n;i++){
        if(cq[i].size()==0)continue;
        for(auto e : ec[i]){  // 色iの辺のみ元の重みにする
            if(depth[id[e.from]] > depth[id[e.to]]){
                update(e.from, e.d);
            }
            else{
                update(e.to, e.d);
            }
        }
        for(auto pp : cq[i]){  // 色iによる重みを引く
            int u = pp.second.first, v = pp.second.second;
            ans[pp.first.second] -= getDist(u, v);
        }
        for(auto e : ec[i]){  // 色iの辺の数を数えるための処理
            if(depth[id[e.from]] > depth[id[e.to]]){
                update(e.from, 1);
            }
            else{
                update(e.to, 1);
            }
        }
        for(auto pp : cq[i]){  // 色iの辺の数だけ重みを加える
            int u = pp.second.first, v = pp.second.second;
            ans[pp.first.second] += getDist(u, v)*pp.first.first;
        }
        for(auto e : ec[i]){  // 辺の重みを0に戻す
            if(depth[id[e.from]] > depth[id[e.to]]){
                update(e.from, 0);
            }
            else{
                update(e.to, 0);
            }
        }
    }
    for(int i=0;i<q;i++){
        cout << ans[i] << endl;
    }
    return 0;
}


Measured memory_bytes: 41012