#pragma gcc optimize("Ofast")

#include <bits/stdc++.h>
using namespace std;
#define pb push_back
#define ff first
#define ss second
typedef pair<int,int> pii;
vector<vector<pair<int, pii>>> G;
vector<int> mxchild, ord, ind, par, head, depth;
vector<pii> val;

template<typename Iter>
ostream& _out(ostream &s, Iter b, Iter e) {
    s<<"[";
    for ( auto it=b; it!=e; it++ ) s<<(it==b?"":" ")<<*it;
    s<<"]";
    return s;
}
template<class T1,class T2>
ostream& operator<<(ostream& out, pair<T1,T2> p) {
    return out << '(' << p.first << ", " << p.second << ')';
}
template<typename T>
ostream& operator <<( ostream &s, const vector<T> &c ) {
     return _out(s,c.begin(),c.end());
}

#ifdef erd1
  #define pprint(x) cerr<<__PRETTY_FUNCTION__<<":"<<__LINE__<<" - "<<(#x)<<"="<<(x)<<endl
#else
  #define pprint(x)
#endif

int dfs1(int x, int p, int d){
    depth[x] = d;
    int sz = 1, msz = 0, mszi = 0;
    for(auto ip: G[x]){
        int i = ip.ff;
        if(i == p)continue;
        val[i] = ip.ss;
        int s = dfs1(i, x, d+1);
        if(s > msz)msz = s, mszi = i;
        sz += s;
    }
    mxchild[x] = mszi;
    return sz;
}
void dfs2(int x, int p, int hd){
    head[x] = hd;
    ind[x] = ord.size();
    par[x] = p;
    ord.pb(x);
    if(mxchild[x])dfs2(mxchild[x], x, hd);
    for(auto ip: G[x]){
        int i = ip.ff;
        if(i == p)continue;
        if(i == mxchild[x])continue;
        dfs2(i, x, i);
    }
}
pii& operator+=(pii& p, pii p2){
    p.ff+=p2.ff;
    p.ss+=p2.ss;
    return p;
}
struct node{
    node *L, *R;
    int l, r, mid, sum;
    map<int, pii> data;

    node(int ll, int rr){
        l = ll, r = rr, mid = l+r >> 1;
        if(l != r){
            L = new node(l, mid), R = new node(mid+1, r);
            for(auto i : L->data){
                pprint(i);
                data[i.ff]+=i.ss;
            }
            for(auto i : R->data){
                pprint(i);
                data[i.ff]+=i.ss;
                pprint(data[i.ff]);
            }
            sum = L->sum + R->sum;
        }else{
            sum = val[ord[mid]].ss;
            data[val[ord[mid]].ff]= {1, val[ord[mid]].ss};
        }
    }
    int query(int ll, int rr, int c, int x){
        if(ll > r || rr < l)return 0;
        if(ll <= l && rr >= r){
            pii d = data.find(c) == data.end() ? make_pair(0, 0): data[c];
            return sum - d.ss + d.ff*x;
        }
        return L->query(ll, rr, c, x)+R->query(ll, rr, c, x);
    }
};
node* root;
signed main(){
    int n, q;
    cin >> n >> q;
    G.resize(n+1);
    mxchild.resize(n+1);
    ind.resize(n+1);
    par.resize(n+1);
    head.resize(n+1);
    val.resize(n+1);
    depth.resize(n+1);
    ord.pb(0);
    for(int i = 1; i < n; i++){
        int a, b, c, d;
        cin >> a >> b >> c >> d;
        G[a].pb({b,{c,d}});
        G[b].pb({a,{c,d}});
    }
    dfs1(1, 0, 0);
    dfs2(1, 0, 0);
    pprint(ind);pprint(par);pprint(head);pprint(val);
    root = new node(1, n);
    while(q--){
        int x, y, u, v;
        cin >> u >> v >> x >> y;
        int ans = 0;
        while(head[x] != head[y]){
            if(depth[head[x]] > depth[head[y]])swap(x, y); // x
            ans += root->query(ind[head[y]], ind[y], u, v);
            pprint(ans);
            y = par[head[y]];
        }
        ans += root->query(min(ind[x], ind[y])+1, max(ind[x], ind[y]), u, v);
        cout << ans << endl;
    }
}


Measured memory_bytes: 107704