#pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
using namespace std;
#define rep(i, n) for(int i = 0; i < (int)(n); ++i)
#define all(x) x.begin(),x.end()
#define ln '\n'
const long double PI = acos(-1.0L);
const long long MOD = 1000000007LL;
// const long long MOD = 998244353LL;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<long long, long long> pll;
template<class T> inline bool chmax(T &a, T b) { if (a < b) { a = b; return true;} return false; }
template<class T> inline bool chmin(T &a, T b) { if (a > b) { a = b; return true;} return false; }
////////////////////////////////////////////////////////////////////////////////////////////////////////////

template<typename T>
struct edge {
    int color,to;
    T cost;

    edge() = default;
    edge(int to, T cost) : color(-1), to(to), cost(cost) {}
    edge(int to, int color, T cost) : to(to), color(color), cost(cost) {}
    bool operator<(const edge &e) const {
        return cost < e.cost;
    }
};

struct EulerTourForEdge{
    int inf = numeric_limits<int>::max();
    int sz;
    vector<int> ds,us,vs,dep,btm;
    vector<pair<int, int>> node;
    vector<vector<int>> G;

    EulerTourForEdge(){}
    EulerTourForEdge(int N):ds(N),us(N),dep(N),G(N){}

    void dfs(int v,int pv,int d){
        dep[v] = d;
        vs.emplace_back(v);
        for(int nv : G[v]) {
            if(nv == pv) continue;
            ds[nv] = btm.size();
            btm.emplace_back(nv);
            dfs(nv,v,d+1);
            us[nv] = btm.size();
            btm.emplace_back(nv);
            vs.emplace_back(v);
        }
    }

    void add_edge(int u, int v){
        G[u].emplace_back(v);
        G[v].emplace_back(u);
    }

    void build(int r = 0){
        btm.clear();
        ds[r] = btm.size();
        btm.emplace_back(r);
        dfs(r,-1,0);
        us[r] = btm.size();
        btm.emplace_back(r);

        sz = 1;
        while (sz < vs.size()) sz *= 2;
        node.assign(2*sz, make_pair(inf,-1));
        for (int i = 0; i < vs.size(); ++i) node[i+sz] = make_pair(dep[vs[i]],vs[i]);
        for (int i = sz-1; i > 0; --i) node[i] = min(node[i<<1|0],node[i<<1|1]);
    }

    pair<int, int> get(int a, int b, int k = 1, int l = 0, int r = -1) {
        if (r < 0) r = sz;

        if (r <= a || b <= l) return make_pair(inf,-1);

        if (a <= l && r <= b) return node[k];

        pair<int, int> vl = get(a, b, k<<1|0, l, (l+r)/2);
        pair<int, int> vr = get(a, b, k<<1|1, (l+r)/2, r);
        return min(vl,vr);
    }

    int lca(int u, int v) {
        if (ds[u] > ds[v]) swap(u,v);
        return get(ds[u],ds[v]+1).second;
    }

    int child(int u,int v){
        return dep[u] < dep[v] ? v : u;
    }
};

template<typename T>
struct SegmentTree {
    int N;
    vector<T> node;

    SegmentTree() = default;
    SegmentTree(vector<T> &v) {init(v);}

    void init(vector<T> &v) {
        N = 1;
        int sz = v.size();
        while (N < sz) N *= 2;
        node.assign(2*N,0);
        for (int i = 0; i < sz; i++) node[i+N] = v[i];
        for (int i = N-1; i >= 1; i--) node[i] = node[i<<1|0] + node[i<<1|1];
    }

    void update(int x, T val) { // (0-indexed)
        x += N;
        node[x] += val;
        while (x > 1) {
            x >>= 1;
            node[x] = node[x<<1|0] + node[x<<1|1];
        }
    }

    T get(int a, int b, int k = 1, int l = 0, int r = -1) { // [a, b) (0-indexed)
        if (r < 0) r = N;

        if (r <= a || b <= l) return 0;
        if (a <= l && r <= b) return node[k];
        T vl = get(a, b, k<<1|0, l, (l+r)/2);
        T vr = get(a, b, k<<1|1, (l+r)/2, r);
        return vl + vr;
    }

    T operator[](int x) {return node[x+N];} 
};

int main() {
    ios::sync_with_stdio(false); cin.tie(nullptr);
    int N,Q; cin >> N >> Q;
    vector<vector<edge<ll>>> G(N);
    EulerTourForEdge ET(N);
    rep(i,N-1) {
        int a,b,c,d; cin >> a >> b >> c >> d;
        --a; --b; --c;
        G[a].emplace_back(b,c,d);
        ET.add_edge(a,b);
    }
    ET.build();
    vector<tuple<int, int, int, int, int>> A(Q);
    rep(i,Q) {
        int x,y,u,v; cin >> x >> y >> u >> v;
        --x; --u; --v;
        A[i] = make_tuple(x,y,u,v,i);
    }

    vector<ll> dist(2*N);
    vector<vector<int>> H(N-1);
    SegmentTree<ll> seg1(dist),seg2(dist);
    rep(i,N) {
        for (auto &e : G[i]) {
            int c = ET.child(i,e.to);
            seg1.update(ET.ds[c],e.cost);
            seg1.update(ET.us[c],-e.cost);
            H[e.color].emplace_back(ET.ds[c]);
            H[e.color].emplace_back(ET.us[c]);
        }
    }

    sort(all(A));
    vector<ll> ans(Q);
    int cur = -1;
    map<int, ll> dic;
    rep(i,Q) {
        int x,y,u,v,id;
        tie(x,y,u,v,id) = A[i];
        if(x != cur) {
            for (auto j : dic) {
                seg1.update(j.first,j.second);
                if (j.second > 0) seg2.update(j.first,-1);
                else seg2.update(j.first,1);
            }
            dic.clear();
            for (auto j : H[x]) {
                ll val = seg1[j];
                seg1.update(j,-val);
                dic.emplace(j,val);
                if (val > 0) seg2.update(j,1);
                else seg2.update(j,-1);
            }
            cur = x;
        }

        int w = ET.lca(u,v);
        ans[id] = seg1.get(ET.ds[w]+1, ET.ds[u]+1) + seg1.get(ET.ds[w]+1, ET.ds[v]+1);
        ans[id] += (seg2.get(ET.ds[w]+1, ET.ds[u]+1) + seg2.get(ET.ds[w]+1, ET.ds[v]+1))*y;
    }

    rep(i,Q) cout << ans[i] << ln;
}

Measured memory_bytes: 49516