#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> Pii;
typedef pair<ll,ll> Pll;
#define rep(i,n) for (ll i=0;i<(n);++i)
#define rep2(i,a,b) for (ll i=(a);i<(b);++i)
#define debug(x) cout << #x << '=' << x << endl
#define all(v) (v).begin(),(v).end()
const ll MOD=1e9+7;
//const ll MOD=998244353;
const ll INF=1e9;
const ll IINF=1e18;
const double EPS=1e-8;
const double pi=acos(-1);

template<class T> inline bool chmin(T &a,T b){
    if (a>b){a=b; return true;} return false;
}
template<class T> inline bool chmax(T &a,T b){
    if (a<b){a=b; return true;} return false;
}

class EularTourForEdge{
    private:
    vector<int> ds,us,dep,btm;
    void dfs(int v,int p,int d){
        dep[v]=d;
        for (int u:G[v]){
            if (u==p) continue;
            ds[u]=btm.size();
            btm.emplace_back(u);
            dfs(u,v,d+1);
            us[u]=btm.size();
            btm.emplace_back(u);
        }
    }
    public:
    vector<vector<int>> G;
    EularTourForEdge(int n):
        ds(n),us(n),dep(n),G(n){}
    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);
    }
    int child(int u,int v){
        return dep[u]<dep[v]?v:u;
    }
    int bottom(int e){
        return btm[e];
    }
    template<typename T,typename F>
    T query(int v,F f){
        return f(0,us[v]);
    }
    //u or v must be lca(u,v)
    template<typename T,typename F>
    T query(int u,int v,F f){
        if (dep[u]<dep[v]) swap(u,v);
        return query<T>(u,f)-query<T>(v,f);
    }
    template<typename T,typename G>
    void update(int v,T x,G g){
        g(ds[v],x);
        g(us[v],-x);
    }
};

struct LowestCommonAncestor{
    int n,h;
    vector<vector<int>> G,par;
    vector<int> dep;
    LowestCommonAncestor(int n):n(n),G(n),dep(n){
        h=1;
        while((1<<h)<=n) ++h;
        par.assign(h,vector<int>(n,-1));
    }
    void add_edge(int u,int v){
        G[u].emplace_back(v);
        G[v].emplace_back(u);
    }
    void dfs(int v,int p,int d){
        par[0][v]=p;
        dep[v]=d;
        for (int u:G[v]){
            if (u!=p) dfs(u,v,d+1);
        }
    }
    void build(int r=0){
        dfs(r,-1,0);
        rep(k,h-1) rep(v,n) if (par[k][v]>=0){
            par[k+1][v]=par[k][par[k][v]];
        }
    }
    int lca(int u,int v){
        if (dep[u]>dep[v]) swap(u,v);
        rep(k,h){
            if ((dep[v]-dep[u])&1<<k) v=par[k][v];
        }
        if (u==v) return u;
        for (int k=h-1;k>=0;--k){
            if (par[k][u]!=par[k][v]) u=par[k][u],v=par[k][v];
        }
        return par[0][u];
    }
    int distance(int u,int v){
        return dep[u]+dep[v]-dep[lca(u,v)]*2;
    }
};

template<typename Monoid>
struct SegmentTree{
    typedef function<Monoid(Monoid,Monoid)> F;
    int n;
    F f;
    Monoid id;
    vector<Monoid> dat;
    SegmentTree(int n_,F f,Monoid id):f(f),id(id){init(n_);}
    void init(int n_){
        n=1;
        while(n<n_) n<<=1;
        dat.assign(n<<1,id);
    }
    void build(const vector<Monoid> &v){
        rep(i,v.size()) dat[i+n]=v[i];
        for (int i=n-1;i;--i) dat[i]=f(dat[i<<1|0],dat[i<<1|1]);
    }
    void update(int k,Monoid a){
        dat[k+=n]=a;
        while(k>>=1) dat[k]=f(dat[k<<1|0],dat[k<<1|1]);
    }
    Monoid query(int a,int b){
        Monoid vl=id,vr=id;
        for (int l=a+n,r=b+n;l<r;l>>=1,r>>=1){
            if (l&1) vl=f(vl,dat[l++]);
            if (r&1) vr=f(dat[--r],vr);
        }
        return f(vl,vr);
    }
    Monoid operator[](int i){
        return dat[i+n];
    }
};

int main(){
    cin.tie(0);
    ios::sync_with_stdio(false);
    int N,Q; cin >> N >> Q;
    EularTourForEdge ET(N);
    LowestCommonAncestor LCA(N);
    vector<int> a(N),b(N),c(N),d(N);
    vector<vector<int>> color(N);
    rep(i,N-1){
        cin >> a[i] >> b[i] >> c[i] >> d[i]; --a[i],--b[i];
        ET.add_edge(a[i],b[i]);
        LCA.add_edge(a[i],b[i]);
        color[c[i]].emplace_back(i);
    }
    ET.build(); LCA.build();
    auto f=[](int a,int b){return a+b;};
    SegmentTree<int> seg0(2*N,f,0),seg1(2*N,f,0);
    auto F0=[&](int l,int r){return seg0.query(l,r);};
    auto F1=[&](int l,int r){return seg1.query(l,r);};
    auto G0=[&](int k,int d){seg0.update(k,d);};
    auto G1=[&](int k,int d){seg1.update(k,d);};
    rep(i,N-1) ET.update(ET.child(a[i],b[i]),d[i],G0);
    struct Query{
        int x,y,u,v,idx;
        Query(int x,int y,int u,int v,int idx):
            x(x),y(y),u(u),v(v),idx(idx){}
        bool operator<(const Query &q){return x<q.x;}
    };
    vector<Query> qs;
    rep(i,Q){
        int x,y,u,v; cin >> x >> y >> u >> v;
        qs.emplace_back(x,y,--u,--v,i);
    }
    sort(all(qs));
    vector<int> ans(Q);
    int color_now=0;
    rep(i,Q){
        if (color_now!=qs[i].x){
            for (int e:color[color_now]){
                ET.update(ET.child(a[e],b[e]),d[e],G0);
                ET.update(ET.child(a[e],b[e]),0,G1);
            }
            color_now=qs[i].x;
            for (int e:color[color_now]){
                ET.update(ET.child(a[e],b[e]),0,G0);
                ET.update(ET.child(a[e],b[e]),1,G1);
            }
        }
        int u=qs[i].u,v=qs[i].v,p=LCA.lca(u,v);
        ans[qs[i].idx]=ET.query<int>(u,p,F0)+ET.query<int>(v,p,F0)
            +(ET.query<int>(u,p,F1)+ET.query<int>(v,p,F1))*qs[i].y;
    }
    rep(i,Q) cout << ans[i] << endl;
}

Measured memory_bytes: 35308