#include <bits/stdc++.h>
#define mset(a, b) memset(a, b, sizeof a)
#define rep(i, a, b) for(int i(a), i##_END_(b); i <= i##_END_; i++) 
#define drep(i, a, b) for(int i(a), i##_END_(b); i >= i##_END_; i--)
using namespace std;
template<class T> inline bool tomax(T &a, T b) {return a < b ? a = b, 1 : 0;}
template<class T> inline bool tomin(T &a, T b) {return b < a ? a = b, 1 : 0;}
typedef long long ll;
typedef double db;

const int N = 1e5 + 5;

template<int N, int M, class T> struct Link { 
#define erep(k, G, o) for(int k(G.HEAD[o]); k; k = G.NXT[k])
    int HEAD[N], NXT[M], tot; T W[M];
    void add(int x, T w) {NXT[++tot] = HEAD[x]; W[HEAD[x] = tot] = w;}
    T& operator[] (int x) {return W[x];}
};
struct Edge {
    int to, w;
};
Link<N, N * 2, Edge> G;

struct Data {
    int u, v, d;
};
vector<Data> col[N];
struct Query {
    int u, v, y, id;
};
vector<Query> qry[N];

struct Segment {
#define mid (L + R >> 1)
#define ls (o << 1)
#define rs (o << 1 | 1)
#define lson ls, L, mid
#define rson rs, mid + 1, R
    int seg[N << 2];
    void build(int a[], int o, int L, int R) {
        if(L == R) {seg[o] = a[L]; return;}
        build(a, lson); build(a, rson);
    }
    int qry(int x, int o, int L, int R) {
        if(L == R) return seg[o];
        if(x <= mid) return qry(x, lson) + seg[o];
        else return qry(x, rson) + seg[o];
    }
    void upd(int l, int r, int v, int o, int L, int R) {
        if(l == L && r == R) {
            seg[o] += v;
            return;
        }
        if(r <= mid) upd(l, r, v, lson);
        else if(l > mid) upd(l, r, v, rson);
        else upd(l, mid, v, lson), upd(mid + 1, r, v, rson);
    }
} sum, tag;

int sz[N], hs[N], fa[N], dfn[N], dep[N], dis[N], cur, en[N], tp[N];
void dfs1(int o, int f) {
    sz[o] = 1; fa[o] = f;
    dep[o] = dep[f] + 1;
    erep(k, G, o) { 
        Edge e = G[k];
        if(e.to == f) continue;
        dis[e.to] = dis[o] + e.w;
        dfs1(e.to, o);
        sz[o] += sz[e.to];
        if(sz[hs[o]] < sz[e.to]) hs[o] = e.to;
    }
}
void dfs2(int o, int f, int t) {
    dfn[o] = ++cur; tp[o] = t;
    if(hs[o]) dfs2(hs[o], o, t);
    erep(k, G, o) {
        int v = G[k].to;
        if(v == f || v == hs[o]) continue;
        dfs2(v, o, v);
    }
    en[o] = cur;
}
int lca(int u, int v) {
    while(tp[u] != tp[v]) {
        if(dep[fa[tp[u]]] < dep[fa[tp[v]]]) swap(u, v);
        u = fa[tp[u]];
    }
    return dep[u] < dep[v] ? u : v;
}

int a[N];
int ans[N];
int main() {
    int n, q;
    scanf("%d%d", &n, &q);
    rep(i, 2, n) {
        int u, v, d, c;
        scanf("%d%d%d%d", &u, &v, &c, &d);
        G.add(u, (Edge) {v, d});
        G.add(v, (Edge) {u, d});
        col[c].push_back((Data) {u, v, d});
    }
    rep(i, 1, q) {
        int x, y, u, v;
        scanf("%d%d%d%d", &x, &y, &u, &v);
        qry[x].push_back((Query) {u, v, y, i});
    }
    dfs1(1, 0); dfs2(1, 0, 1);
    rep(i, 1, n) a[dfn[i]] = dis[i];
    sum.build(a, 1, 1, n);
    rep(i, 1, n - 1) {
        for(Data d : col[i]) {
            int o = (fa[d.u] == d.v ? d.u : d.v);
            sum.upd(dfn[o], en[o], -d.d, 1, 1, n);
            tag.upd(dfn[o], en[o], 1, 1, 1, n);
        }
        for(Query d : qry[i]) {
            int p = lca(d.u, d.v);
            int s = sum.qry(dfn[d.u], 1, 1, n) + sum.qry(dfn[d.v], 1, 1, n) - 2 * sum.qry(dfn[p], 1, 1, n);
            int t = tag.qry(dfn[d.u], 1, 1, n) + tag.qry(dfn[d.v], 1, 1, n) - 2 * tag.qry(dfn[p], 1, 1, n);
            ans[d.id] = s + t * d.y;
        }
        for(Data d : col[i]) {
            int o = (fa[d.u] == d.v ? d.u : d.v);
            sum.upd(dfn[o], en[o], d.d, 1, 1, n);
            tag.upd(dfn[o], en[o], -1, 1, 1, n);
        }
    }
    rep(i, 1, q) printf("%d\n", ans[i]);
    return 0;
}


Measured memory_bytes: 23988