// おーばーきる
#include <bits/stdc++.h>

using namespace std;

using ll = long long;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
using vi = vector<int>;
using vl = vector<ll>;

using _loop_int = int;
#define REP(i, n) for(_loop_int i = 0; i < (_loop_int)(n); i++)
#define FOR(i, a, b) for(_loop_int i = (_loop_int)(a); i < (_loop_int)(b); i++)
#define FORR(i, a, b) for(_loop_int i = (_loop_int)(b)-1; i >= (_loop_int)(a); i--)

#define CHMIN(a, b) (a) = min((a), (b))
#define CHMAX(a, b) (a) = max((a), (b))
#define ALL(v) (v).begin(), (v).end()

#define DEBUG(x) cerr << #x << ": " << (x) << endl
#define DEBUG_VEC(v)                                 \
    cerr << #v << ": ";                              \
    REP(__i, (v).size()) cerr << ((v)[__i]) << ", "; \
    cerr << endl

const ll MOD = 1000000007ll;

// 永続配列
struct node {
    int lch, rch;
    int val, version;
};
node *nodes;
int nodehead;
bool inited = false;
void nodesinit() {
    if(inited)return;
    nodehead = 0;
    nodes = (node *)calloc(16000000, sizeof(node));
    inited = true;
}
int mynew(int val, int version) {
    nodesinit();
    nodes[nodehead].val = val;
    nodes[nodehead].version = version;
    nodes[nodehead].lch = nodes[nodehead].rch = -1;
    return nodehead++;
}
#define SIZE 131072
#define VMAX 100002
#define DEFAULT 0
struct myarray {
    int now;
    int mx;
    int *rootid;
    myarray() : now(0),mx(0) {
        rootid = (int *)calloc(VMAX, sizeof(int));
        rootid[0] = mynew(DEFAULT, 0);
    }
    int getat(int v, int k) {
        int l = 0, r = SIZE;
        int curid = rootid[v];
        while(l + 1 < r) {
            int c = (l + r) >> 1;
            if(k < c) {
                if(nodes[curid].lch == -1) return DEFAULT;
                r = c;
                curid = nodes[curid].lch;
            } else {
                if(nodes[curid].rch == -1) return DEFAULT;
                l = c;
                curid = nodes[curid].rch;
            }
        }
        return nodes[curid].val;
    }
    int setat_rec(int curid, int v, int k, int x, int l, int r, int id) {
        if(l + 1 == r) {
            if(nodes[curid].version == v) {
                nodes[curid].val = x;
                return curid;
            } else {
                return mynew(x, v);
            }
        } else {
            int c = (l + r) >> 1;
            if(k < c) {
                int nxt = 0;
                if(nodes[curid].lch == -1) {
                    int lch = mynew(DEFAULT, v);
                    nxt = setat_rec(lch, v, k, x, l, c, (id << 1) + 1);
                } else {
                    nxt = setat_rec(nodes[curid].lch, v, k, x, l, c, (id << 1) + 1);
                }
                if(nodes[curid].version == v) {
                    nodes[curid].lch = nxt;
                    return curid;
                } else {
                    int ret = mynew(DEFAULT, v);
                    nodes[ret].rch = nodes[curid].rch;
                    nodes[ret].lch = nxt;
                    return ret;
                }
            } else {
                int nxt = 0;
                if(nodes[curid].rch == -1) {
                    int rch = mynew(DEFAULT, v);
                    nxt = setat_rec(rch, v, k, x, c, r, (id << 1) + 2);
                } else {
                    nxt = setat_rec(nodes[curid].rch, v, k, x, c, r, (id << 1) + 2);
                }
                if(nodes[curid].version == v) {
                    nodes[curid].rch = nxt;
                    return curid;
                } else {
                    int ret = mynew(DEFAULT, v);
                    nodes[ret].lch = nodes[curid].lch;
                    nodes[ret].rch = nxt;
                    return ret;
                }
            }
        }
    }
    void setat(int v, int k, int x) { rootid[v] = setat_rec(rootid[v], v, k, x, 0, SIZE, 0); }
    void dup(int from) {
        rootid[mx + 1] = mynew(DEFAULT, mx + 1);
        nodes[rootid[mx + 1]].lch = nodes[rootid[from]].lch;
        nodes[rootid[mx + 1]].rch = nodes[rootid[from]].rch;
        mx += 1;
    }
};

struct HeavyLightDecomposition {
    static const int root = 0;
    // tree representation
    int N;           // size
    vi parent;       // parent[p] := parent of node p
    vi depth;        // depth[p] := depth of node p
    vi subtreesize;  // subtreesize[p] := size of subtree rooted at node p

    // heavy light decomposition
    vector<vi> paths;  // paths[i] := heavy edge path (id=i)
    vi belongs;        // belongs[p] := id of path that node p belongs to
    vi pathpos;  // pathpos[p] := index of node p in paths[belongs[p]] (paths[belongs[p]][pathpos[p]] == p) (for segment
                 // tree)
    vi heavyedge;  // heavyedge[p] := edge (p,heavyedge[p]) is heavy edge

    // tree construct dfs
    int treedfs(int p, int d, int bef, vi g[]) {
        parent[p] = bef;
        depth[p] = d;
        subtreesize[p] = 1;
        int maxchild = -1;
        REP(i, g[p].size()) {
            int to = g[p][i];
            if(to == bef) continue;
            subtreesize[p] += treedfs(to, d + 1, p, g);
            if(maxchild == -1 || subtreesize[maxchild] < subtreesize[to]) {
                maxchild = to;
            }
        }
        if(maxchild != -1 && subtreesize[maxchild] * 2 >= subtreesize[p]) {
            heavyedge[p] = maxchild;
        }
        return subtreesize[p];
    }

    // heavy light decomposition dfs
    void decompositiondfs(int pathid, int head, int bef, vi g[]) {
        paths.push_back(vi());
        int cur = head;
        while(true) {
            belongs[cur] = pathid;
            pathpos[cur] = paths[pathid].size();
            paths[pathid].push_back(cur);
            int nxt = heavyedge[cur];
            REP(i, g[cur].size()) {
                int to = g[cur][i];
                if(to == bef) continue;
                if(to == nxt) continue;
                decompositiondfs(paths.size(), to, cur, g);
            }
            if(nxt == -1) break;
            bef = cur;
            cur = nxt;
        }
    }

    HeavyLightDecomposition(int n, vi g[]) {
        N = n;
        parent.assign(n, -1);
        depth.assign(n, -1);
        subtreesize.assign(n, -1);
        belongs.assign(n, -1);
        pathpos.assign(n, -1);
        heavyedge.assign(n, -1);

        treedfs(root, 0, -1, g);
        decompositiondfs(0, root, -1, g);
    }

    int lca(int a, int b) {
        int ato = paths[belongs[a]][0];
        int bto = paths[belongs[b]][0];
        while(belongs[a] != belongs[b]) {
            if(depth[ato] > depth[bto]) {
                a = ato;
                if(a != root) {
                    a = parent[a];
                    ato = paths[belongs[a]][0];
                }
            } else {
                b = bto;
                if(b != root) {
                    b = parent[b];
                    bto = paths[belongs[b]][0];
                }
            }
        }
        if(depth[a] <= depth[b]) {
            return a;
        } else {
            return b;
        }
    }
};

int n,q;

vector<pair<int,pii>> g[125252];
vi g2[125252];

ll sum[125252];
myarray cnt,sss;
int ver[125252];
void dfs(int p, int bef, ll v, int src){
    // DEBUG(p);
    sum[p] = v;
    ver[p] = src;
    for(auto PP : g[p]){
        int to = PP.first;
        if(to==bef)continue;
        int c = PP.second.first;
        int d = PP.second.second;
        cnt.dup(src);
        sss.dup(src);
        int nid = cnt.mx;
        cnt.setat(nid,c,cnt.getat(src,c)+1);
        sss.setat(nid,c,sss.getat(src,c)+d);
        ll nv = v + d;
        dfs(to,p,nv,nid);
    }
}

int main() {
    scanf("%d%d", &n, &q);
    REP(i,n-1){
        int a,b,c,d;
        scanf("%d%d%d%d",&a,&b,&c,&d);
        --a; --b; --c;
        g[a].push_back(make_pair(b,pii(c,d)));
        g[b].push_back(make_pair(a,pii(c,d)));
        g2[a].push_back(b);
        g2[b].push_back(a);
    }

    HeavyLightDecomposition hld(n,g2);
    dfs(0,-1,0ll,0);

    // REP(i,n)DEBUG(ver[i]);

    while(q--){
        int x,y,u,v;
        scanf("%d%d%d%d",&x,&y,&u,&v);
        --x; --u;--v;
        int lca = hld.lca(u,v);
        ll s = sum[u] + sum[v] - 2*sum[lca];
        // DEBUG(lca);DEBUG(ver[lca]);
        // DEBUG(u); DEBUG(ver[u]);
        // DEBUG(v); DEBUG(ver[v]);
        // DEBUG(s);
        s -= (sss.getat(ver[u],x) + sss.getat(ver[v],x) - 2*sss.getat(ver[lca],x));
        // DEBUG(s);
        s += (cnt.getat(ver[u],x) + cnt.getat(ver[v],x) - 2*cnt.getat(ver[lca],x)) * y;
        // DEBUG(s);
        printf("%lld\n",s);
    }
    return 0;
}


Measured memory_bytes: 85812