#include <stdio.h>
#include <string>
#include <cstring>
#include <stdlib.h>
#include <math.h>
#include <algorithm>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <list>
#include <iterator>
#include <assert.h>
#pragma warning(disable:4996) 

typedef long long ll;
#define MIN(a, b) ((a)>(b)? (b): (a))
#define MAX(a, b) ((a)<(b)? (b): (a))
#define LINF 9223300000000000000
#define INF 2140000000
const long long MOD = 1000000007;
using namespace std;


vector<vector<pair<int,int> > > g;   // to, edgeID
vector<int> depth;           // 各vertex の depth
vector<vector<int> > anc;    // anc[i][j]: vertex i の 2^j個上の祖先

// preparation to get LCA
void dfs0( int par, int curr, vector<int>& vv )   // vv: rootからのnode列、anc: 1,2,4,8,..上の祖先
{
    depth[curr]=(int)vv.size();
    int k=1;
    while(k<=depth[curr]) {
        anc[curr].push_back(vv[depth[curr]-k]);
        k*=2;
    }

    vv.push_back( curr );
    int siz=(int)g[curr].size();
    int i;
    for(i=0; i<siz; i++) {
        int next = g[curr][i].first;
        if( next != par ) {
            dfs0( curr, next, vv );
        }
    }
    vv.pop_back();
    return;
}

int getLCA( int a, int b )
{
    if(depth[a]>depth[b]) swap(a, b);
    int delta = depth[b]-depth[a];
    int cnt=0;
    while(delta>0) {
        if(delta & (1<<cnt)) {
            b = anc[b][cnt];
            delta -= (1<<cnt);
        }
        cnt++;
    }
    assert(depth[a]==depth[b]);
    if(a==b) return a;

    int N=(int)anc[a].size();
    int i;
    for(i=N-1; i>=0; i--) {
        if((int)anc[a].size()>i) {
            if(anc[a][i]!=anc[b][i]) {
                a = anc[a][i];
                b = anc[b][i];
            }
        }
    }
    return anc[a][0];
}

int n,q;
vector<int> c,d;   // data for each edge
vector<int> x,y;   // data for each query
vector<ll>  ans;   // answer for each query

vector<int> cnt;   // current edge num in the path from root for each color
vector<ll> dist;   // current dist sum in the path from root for each color 
ll dist0;          // current dist from root

vector<vector<pair<int,int> > > chk;   // chk[i](0<=i<n): (queryID, mult)の列   ※mult：ansに反映させるときの多重度。1または-2を設定。

void dfs( int par, int curr)
{
    int siz=(int)chk[curr].size();
    int i;
    for(i=0; i<siz; i++) {
        int id = chk[curr][i].first;
        int mult = chk[curr][i].second;
        ans[id] += mult*(dist0 - dist[x[id]] + cnt[x[id]] * y[id]);
    }

    for(i=0; i<(int)g[curr].size(); i++) {
        int next = g[curr][i].first;
        int edge = g[curr][i].second;
        if( next != par ) {
            cnt[c[edge]]++;
            dist[c[edge]]+=d[edge];
            dist0+=d[edge];
            dfs( curr, next );
            cnt[c[edge]]--;
            dist[c[edge]]-=d[edge];
            dist0-=d[edge];
        }
    }
    return;
}

int main(int argc, char* argv[])
{
    scanf("%d%d", &n, &q);
    g.resize(n); depth.resize(n); anc.resize(n);
    c.resize(n-1); d.resize(n-1);

    int i;
    for(i=0; i<n-1; i++) {
        int a,b;
        scanf("%d%d%d%d", &a, &b, &c[i], &d[i]);
        g[a-1].push_back(make_pair(b-1,i));
        g[b-1].push_back(make_pair(a-1,i));
    }

    vector<int> vv;
    dfs0(-1, 0, vv );    // preparation to get LCA

    chk.resize(n);
    x.resize(q); y.resize(q); ans.resize(q);
    for(i=0; i<q; i++) {
        int u,v;
        scanf("%d%d%d%d", &x[i], &y[i], &u, &v);
        u--; v--;
        int a = getLCA(u,v);
        chk[u].push_back(make_pair(i,1));
        chk[v].push_back(make_pair(i,1));
        chk[a].push_back(make_pair(i,-2));
    }

    cnt.resize(n); dist.resize(n);
    dfs(-1, 0);

    for(i=0; i<q; i++) {
        printf("%lld\n", ans[i]);
    }
    return 0;
}


Measured memory_bytes: 32248