#include <bits/stdc++.h>

#define reint register int
#define coint const int

using namespace std;

typedef long long ll;

coint SIZE = 100000 + 5;

struct Edge { int v, w, head; };

int  ecnt, head[SIZE];
Edge edge[SIZE << 1];

inline void addEdge(coint u, coint v, coint w) {
    edge[++ecnt] = (Edge){v, w, head[u]}, head[u] = ecnt;
    return;
}

int tick, dfn[SIZE], post[SIZE], bel[SIZE];
int hfa[SIZE], hson[SIZE], sz[SIZE], dep[SIZE], fa[SIZE];

ll dis[SIZE];

struct BinaryIndexedTree {
    ll li[SIZE];

    inline int lowbit(coint num) { return num & (-num); }
    BinaryIndexedTree(void) { memset(li, 0, sizeof li); return; }

    inline void modify(coint ind, coint k) {
        for (reint i = ind; i < SIZE; i += lowbit(i)) li[i] += k;
        return;
    }

    inline ll query(coint ind) {
        register ll res = 0;
        for (reint i = ind; i; i -= lowbit(i)) res += li[i];
        return res;
    }
};

BinaryIndexedTree sgtr1, sgtr2;

void dfs(coint u) {
    dfn[u] = ++tick, bel[tick] = u, sz[u] = 1;
    for (int i = head[u]; ~i; i = edge[i].head) {
        coint v = edge[i].v;
        if (v == fa[u]) continue;
        dis[v] = dis[u] + edge[i].w, fa[v] = u, dep[v] = dep[u] + 1;
        dfs(v), sz[u] += sz[v];
        if (sz[hson[u]] < sz[v]) hson[u] = v;
    }
    hfa[hson[u]] = u, post[u] = tick;
    return;
}

void dfs2(coint u) {
    hfa[u] = (hfa[u] ? hfa[fa[u]] : u);
    for (int i = head[u]; ~i; i = edge[i].head) {
        coint v = edge[i].v;
        if (v == fa[u]) continue;
        dfs2(v);
    }
    return;
}

inline int lca(reint a, reint b) {
    reint t;
    for (; hfa[a] != hfa[b]; b = fa[hfa[b]])
        if (dep[hfa[a]] > dep[hfa[b]]) t = a, a = b, b = t;
    return dep[a] > dep[b] ? b : a;
}

inline int getint(void) {
    reint x = 0, ch = getchar();
    for (; ch < '0' || ch > '9'; ch = getchar());
    for (; ch >= '0' && ch <= '9';
            x = (x << 1) + (x << 3) + (ch - '0'), ch = getchar());
    return x;
}

struct Query { int b, c, d, ind; };

vector<int> vec1[SIZE], vec2[SIZE], vec3[SIZE];
vector<Query> query[SIZE];
ll ans[SIZE];
int n, q;

inline ll queryxy(coint x, coint y, BinaryIndexedTree &bit) {
    coint xlca = lca(x, y);
    return bit.query(dfn[x]) + bit.query(dfn[y])
           - (bit.query(dfn[xlca]) << 1);
}

int main(void) {
    ecnt = 0, memset(head, -1, sizeof head);
    n = getint(), q = getint();
    for (reint i = 1; i < n; ++i) {
        coint u = getint(), v = getint(), a = getint(), b = getint();
        vec1[a].push_back(u), vec2[a].push_back(v), vec3[a].push_back(b);
        addEdge(u, v, b), addEdge(v, u, b);
    }
    dfs(1), dfs2(1);
    for (reint i = 1; i <= q; ++i) {
        coint x = getint(), y = getint(), u = getint(), v = getint();
        query[x].push_back((Query){y, u, v, i});
    }
    for (reint i = 1; i < n; ++i) {
        coint szq = query[i].size(), sze = vec1[i].size();
        for (reint j = 0; j < sze; ++j) {
            int u = vec1[i][j], v = vec2[i][j], w = vec3[i][j];
            if (dep[u] > dep[v]) swap(u, v);
            sgtr1.modify(dfn[v], -w), sgtr1.modify(post[v] + 1, w);
            sgtr2.modify(dfn[v], 1), sgtr2.modify(post[v] + 1, -1);
        }
        for (reint j = 0; j < szq; ++j) {
            coint y = query[i][j].b, u = query[i][j].c, v = query[i][j].d;
            coint ind = query[i][j].ind;
            ans[ind] = queryxy(u, v, sgtr1) + queryxy(u, v, sgtr2) * y +
                       dis[u] + dis[v] - (dis[lca(u, v)] << 1);
        }
        for (reint j = 0; j < sze; ++j) {
            int u = vec1[i][j], v = vec2[i][j], w = vec3[i][j];
            if (dep[u] > dep[v]) swap(u, v);
            sgtr1.modify(dfn[v], w), sgtr1.modify(post[v] + 1, -w);
            sgtr2.modify(dfn[v], -1), sgtr2.modify(post[v] + 1, 1);
        }
    }

    for (reint i = 1; i <= q; ++i) printf("%lld\n", ans[i]);

    return 0;
}



Measured memory_bytes: 29168