#include<bits/stdc++.h>
using namespace std;
#define ALL(x) x.begin(),x.end()
#define rep(i,n) for(int i=0;i<(n);i++)
#define debug(v) cout<<#v<<":";for(auto x:v){cout<<x<<' ';}cout<<endl;
#define INF 1000000000
#define mod 1000000007
using ll=long long;
const ll LINF=1001002003004005006ll;
int dx[]={1,0,-1,0};
int dy[]={0,1,0,-1};
// ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
template<class T>bool chmax(T &a,const T &b){if(a<b){a=b;return true;}return false;}
template<class T>bool chmin(T &a,const T &b){if(b<a){a=b;return true;}return false;}

typedef vector<vector<int>> graph;
struct DoublingLowestCommonAncestor{
    const int LOG;
    vector<int> dep;
    const graph &g;
    //table[i][j]は点jの2^i個上の親情報
    vector<vector<int>> table;
 
    DoublingLowestCommonAncestor(const graph &g):g(g),dep(g.size()),LOG(32-__builtin_clz(g.size())){
        table.assign(LOG,vector<int>(g.size(),-1));
    }
 
    void dfs(int idx,int par,int d){
        //1個上の親の記録
        table[0][idx]=par;
        dep[idx]=d;
        for(auto &to:g[idx]){
            if(to!=par) dfs(to,idx,d+1);
        }
    }
 
    //根としたい点をroot
    void build(int root){
        dfs(root,-1,0);
        for(int k=0;k+1<LOG;k++){
            for(int i=0;i<table[k].size();i++){
                if(table[k][i]==-1) table[k+1][i]=-1;
                else table[k+1][i]=table[k][table[k][i]];
            }
        }
    }
 
    //u,vのlcaを求める
    int query(int u,int v){
        //dep[u]>dep[v]として進める
        if(dep[u]>dep[v]) swap(u,v);
        //深さをそろえる
        for(int i=LOG-1;i>=0;i--){
            if(((dep[v]-dep[u])>>i)&1) v=table[i][v];
        }
        if(u==v) return u;
        for(int i=LOG-1;i>=0;i--){
            if(table[i][u]!=table[i][v]){
                u=table[i][u];
                v=table[i][v];
            }
        }
        return table[0][u];
    }
    
    //呼び出すたびO(logn)
    int dis(int u,int v){
        int p=query(u,v);
        return dep[u]+dep[v]-2*dep[p];
    }
 
    //いるか？これ
    int operator[](const int &k) const{
        return dep[k];
    }
 
    //頂点xのk個上の親を求める。無ければ-1，未verify
    int parent(int x,int k){
        int ret=x;
        int bit=0;
        for(int i=LOG-1;i>=0 and ret>=0;i--){
            if((k>>i)&1) ret=table[i][ret];
        }
        return ret;
    }
};


template<typename Monoid>
struct SegmentTree{
    using F=function<Monoid(Monoid,Monoid)>;
    int sz;
    vector<Monoid> seg;
    const F f;
    const Monoid gen;
    SegmentTree(int n,const F f,const Monoid &gen):f(f),gen(gen){
        sz=1;
        while(sz<n)sz<<=1;
        seg.assign(2*sz,gen);
    }
    void set(int k,const Monoid &x){
        seg[k+sz]=x;
    }
    void build(){
        for(int k=sz-1;k>0;k--) seg[k]=f(seg[2*k],seg[2*k+1]);
    }
    void update(int k,const Monoid &x){
        k+=sz;
        seg[k]=x;
        while(k>>=1) seg[k]=f(seg[2*k],seg[2*k+1]);
    }
   // [a,b)
    Monoid query(int a,int b){
        Monoid L=gen,R=gen;
        for(a+=sz,b+=sz;a<b;a>>=1,b>>=1){
            if(a&1) L=f(L,seg[a++]);
            if(b&1) R=f(seg[--b],R);
        }
        return f(L,R);
    }
    Monoid operator[](const int &k)const {
       return seg[k+sz];
    }
};
ll segf(ll a,ll b){
    return a+b;
}



int n,q;
struct edge{
    int to,c;ll cost;
    edge(){}
    edge(int to,int c,ll cost):to(to),c(c),cost(cost){}
};
struct query{
    int u,v,id;ll cost;
    query(){}
    query(int u,int v,ll cost,int id):u(u),v(v),cost(cost),id(id){}
};

vector<vector<edge>> g;
graph G;
vector<int> l,r,et;
vector<ll> v,clr;

int pos;
void dfs(int pre,int now){
    l[now]=pos++;et.push_back(now);
    for(auto &e:g[now])if(e.to!=pre){
        v.push_back(e.cost);
        clr.push_back(e.c);
        dfs(now,e.to);
        et.push_back(now);
        v.push_back(-e.cost);
        clr.push_back(-e.c);
    }
    r[now]=pos++;
}



signed main(){
    cin.tie(0);
    ios::sync_with_stdio(0);
    
    int n,q;cin>>n>>q;
    g.resize(n);l.resize(n);r.resize(n);G.resize(n);
    rep(i,n-1){
        int u,v,c;ll cost;cin>>u>>v>>c>>cost;u--,v--;
        G[u].push_back(v);
        G[v].push_back(u);
        g[u].push_back(edge(v,c,cost));
        g[v].push_back(edge(u,c,cost));
    }

    DoublingLowestCommonAncestor lca(G);lca.build(0);
    
    vector<vector<query>> qs(n+1);
    rep(i,q){
        int c,u,v;ll cost;cin>>c>>cost>>u>>v;u--,v--;
        qs[c].push_back(query(u,v,cost,i));
    }

    dfs(-1,0);

    // debug(et);
    // debug(l);
    // debug(r);
    // debug(v);
    // debug(clr);

    vector<vector<pair<int,int>>> onoff(n+1);
    rep(i,2*n-2){
        int cabs=abs(clr[i]);
        if(clr[i]<0) onoff[cabs].push_back(make_pair(i,-1));
        else         onoff[cabs].push_back(make_pair(i,1));
    }



    SegmentTree<ll> seg(2*n-2,segf,0),ko(2*n-2,segf,0);
    rep(i,2*n-2) seg.set(i,v[i]);
    seg.build();
    ko.build();
    

    vector<ll> ans(q);
    for(int i=1;i<=n;i++){
        
        for(auto p:onoff[i]){
            ko.update(p.first,p.second);
            seg.update(p.first,0);
        }

        // cout<<"Color : "<<i<<endl;
        // rep(i,2*n-2) cout<<seg[i]<<" ";cout<<endl;
        // rep(i,2*n-2) cout<<ko[i]<<" ";cout<<endl;

        for(auto qu:qs[i]){
            int par=lca.query(qu.u,qu.v);
            ll res=seg.query(l[par],l[qu.u])+seg.query(l[par],l[qu.v]);
            ll k=ko.query(l[par],l[qu.u])+ko.query(l[par],l[qu.v]);
            // cout<<"par: "<<par<<" res: "<<res<<" k: "<<k<<endl;
            // cout<<"par -> u on et "<<l[par]<<" -> "<<l[qu.u]<<endl;
            // cout<<"par -> v on et "<<l[par]<<" -> "<<l[qu.v]<<endl;
            // cout<<endl;
            ans[qu.id]=res+k*qu.cost;
        }
        for(auto p:onoff[i]){
            seg.update(p.first,v[p.first]);
            ko.update(p.first,0);
        }
    }

    for(auto a:ans)cout<<a<<endl;
    return 0;
}


Measured memory_bytes: 50544