#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MAXN=1e5+5;
const ll MAXQ=1e5+5;
const ll MOD=1e9+7;
const ll MOD1=13;
ll n,q,root[MAXN],cnt,depth[MAXN];
struct record
{
    ll x,y,u,v;
}rec[MAXN];
struct node
{
    ll l,r,num,sum;
}T[MAXN*40];
struct tp
{
    ll v,c,w;
};
ll answer[MAXQ],tt,h[MAXQ];
struct Query
{
    ll q,next,index;
}queries[MAXQ*2];//这里要把一个询问当两个加入是因为我们需要在处理完u的时候处理完所有与u相关的询问
vector<tp>G[MAXN];
//LCA
ll f[MAXN];//并查集的本质是分组这种数据结构 而不是树这种递归结构
void init()
{
    for(ll i=1;i<=n;i++)
    {
        f[i]=i;
    }
}
ll findfather(ll x)
{
    if(x!=f[x])
    {
        f[x]=findfather(f[x]);
    }
    return f[x];
}
void mergefather(ll x,ll y)
{
    ll t1=findfather(x);
    ll t2=findfather(y);
    if(t1!=t2)
    {
        f[t1]=t2;
    }
}

void addquery(ll u,ll v,ll index)
{
    queries[++tt].q=v;
    queries[tt].next=h[u];
    queries[tt].index=index;
    h[u]=tt;
}
ll vis[MAXN],ancestor[MAXN];
void lca(ll u,ll dep)//我们在u子树访问结束的时候处理和u相关的所有询问中另外一方也已经访问结束的部分 这时候两者处于lca之下
{
    depth[u]=dep;
    ancestor[u]=u;
    vis[u]=1;
    for(ll i=0;i<G[u].size();i++)
    {
        ll v=G[u][i].v;
        ll w=G[u][i].w;
        if(vis[v])
        {
            continue;
        }
        lca(v,dep+w);
        mergefather(u,v);//这里在v子树返回的时候将两个合并
        ancestor[findfather(u)]=u;//
    }
    for(ll i=h[u];i;i=queries[i].next)
    {
        ll v=queries[i].q;
        if(vis[v])
        {
            answer[queries[i].index]=ancestor[findfather(v)];
        }
    }
}

//主席树
void update(ll c,ll w,ll l,ll r,ll &x,ll y)
{
    T[++cnt]=T[y];T[cnt].num++;T[cnt].sum+=w;x=cnt;
    if(l==r)
    {
        return;
    }
    ll mid=(l+r)/2;

    if(c<=mid)
    {
        update(c,w,l,mid,T[cnt].l,T[y].l);
    }
    else
    {
        update(c,w,mid+1,r,T[cnt].r,T[y].r);
    }
}
pair<ll,ll> query(ll p,ll l,ll r,ll x,ll y)
{
    if(l==r)
    {
        return make_pair(T[y].num-T[x].num,T[y].sum-T[x].sum);
    }
    ll mid=(l+r)/2;

    if(p<=mid)
    {
        return query(p,l,mid,T[x].l,T[y].l);
    }
    else
    {
        return query(p,mid+1,r,T[x].r,T[y].r);
    }
}
void build(ll u,ll pre)
{
    for(ll i=0;i<G[u].size();i++)
    {
        ll v=G[u][i].v;
        ll c=G[u][i].c;
        ll w=G[u][i].w;
        if(v==pre)
        {
            continue;
        }
        update(c,w,1,n-1,root[v],root[u]);
        build(v,u);
    }
}
void solve()
{
    build(1,0);
    //pair<ll,ll>ret=query(1,1,1,root[1],root[3]);


    lca(1,0);
    for(ll i=1;i<=q;i++)
    {
        ll lca=answer[i];

        ll u=rec[i].u,v=rec[i].v,x=rec[i].x,y=rec[i].y;

        ll origin=depth[u]+depth[v]-2*depth[lca];

        pair<ll,ll> ret1=query(x,1,n-1,root[lca],root[u]);
        pair<ll,ll> ret2=query(x,1,n-1,root[lca],root[v]);

        ll det=-(ret1.second+ret2.second)+y*(ret1.first+ret2.first);


        printf("%lld\n",origin+det);
    }
}
int main()
{
    while(~scanf("%lld %lld",&n,&q))
    {
        init();
//        string str;
//        cin>>str;
//        cout<<str<<endl;
        for(ll i=1;i<n;i++)
        {
            ll a,b,c,d;
            scanf("%lld %lld %lld %lld",&a,&b,&c,&d);
            G[a].push_back(tp{b,c,d});
            G[b].push_back(tp{a,c,d});
        }
        for(ll i=1;i<=q;i++)
        {
            ll x,y,u,v;
            scanf("%lld %lld %lld %lld",&x,&y,&u,&v);
            addquery(u,v,i);
            addquery(v,u,i);
            rec[i]=record{x,y,u,v};
        }
        solve();
    }
}
/*
3 2
1 2 1 1
2 3 1 2


3 2
1 2 1 1
1 3 2 2
2 1 1 3
1 2 2 3
*/


Measured memory_bytes: 86144