#include <bits/stdc++.h>
#define rep(i,n) for(int i = 0; i < (n); ++i)
#define rrep(i,n) for(int i = 1; i <= (n); ++i)
#define drep(i,n) for(int i = (n)-1; i >= 0; --i)
#define srep(i,s,t) for (int i = s; i < t; ++i)
#define rng(a) a.begin(),a.end()
using namespace std;
typedef long long int ll;
typedef pair<int,int> P;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<ll> vl;
typedef vector<P> vp;

struct edge{ int to, cost, color, id; };

#define MAX_N 200005
vector<edge> pre_G[MAX_N];
vector<edge> G[MAX_N];
int par_[MAX_N];
int flag_netsukigi[MAX_N];
void make_netsukigi(int r){
    queue<int> que;
    que.push(r);
    flag_netsukigi[r] = 1;
    par_[r] = -1;

    while(que.size() > 0){
        int x = que.front();
        que.pop();
        flag_netsukigi[x] = 1;
        rep(i,pre_G[x].size()){
            if(flag_netsukigi[pre_G[x][i].to] == 0){
                par_[pre_G[x][i].to] = x;
                G[x].push_back(pre_G[x][i]);
                que.push(pre_G[x][i].to);
            }
        }
    }
}

#define MAXN 200005

int block_sz;          // block size = sqrt(height)
int depth[MAXN];       // stores depth for each node.
int parent[MAXN];      // stores first parent for each node.
int jump_parent[MAXN]; // stores first ancestor in previous block.
vector<int> adj[MAXN];

void addEdge(int u, int v){
    adj[u].push_back(v);
    adj[v].push_back(u);
}

int LCANaive(int u,int v){
    if(u == v)              return u;
    if(depth[u] > depth[v]) swap(u, v);
    v = parent[v];
    return LCANaive(u, v);
}

// precalculating the required parameters associated with every node.
void dfs(int cur, int prev){
    // marking depth of cur node
    depth[cur] = depth[prev] + 1;
    
    // marking parent of cur node
    parent[cur] = prev;
    
    // making jump_parent of cur node
    // if it is first node of the block then its jump_parent is its cur parent.
    if (depth[cur] % block_sz == 0) jump_parent[cur] = parent[cur];
    // if it is not the first node of this block then its jump_parent is jump_parent of its parent.
    else                            jump_parent[cur] = jump_parent[prev];
    
    // propogating the marking down the subtree
    for(int i = 0; i < adj[cur].size(); ++i) if(adj[cur][i] != prev) dfs(adj[cur][i], cur);
}

// using sqrt decomposition trick
int LCASQRT(int u, int v){
    while(jump_parent[u] != jump_parent[v]){
        // maintaining depth[v] > depth[u]
        if(depth[u] > depth[v]) swap(u, v);
        // climb to its jump parent
        v = jump_parent[v];
    }
    // u and v have same jump_parent
    return LCANaive(u, v);
} 

void preprocess(int height){
    block_sz = sqrt(height);
    depth[0] = -1;
    // precalclating 1) depth.  2) parent.  3) jump_parent for each node
    dfs(0, 0);
}


vector<P> euler_tour;
vector<int> euler_color[MAX_N], euler_sum[MAX_N], euler_num[MAX_N];
int dist[MAX_N], place[MAX_N];
int now_dist;
int cnt;
void dfs_euler_tour(int x){
    dist[x] = now_dist;
    place[x] = cnt;
    rep(i,G[x].size()){
        euler_tour.push_back(P(G[x][i].cost,1));
        euler_color[G[x][i].color].push_back(cnt);
        cnt++;
        now_dist += G[x][i].cost;
        dfs_euler_tour(G[x][i].to);
        euler_tour.push_back(P(G[x][i].cost,-1));
        euler_color[G[x][i].color].push_back(cnt);
        cnt++;
        now_dist -= G[x][i].cost;
    }
}
void init_euler_tour(){
    dfs_euler_tour(0);
}



int main(){
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    int n, q;
    cin >> n >> q;
    int a[n-1], b[n-1], c[n-1], d[n-1];
    rep(i,n-1){
        cin >> a[i] >> b[i] >> c[i] >> d[i];
        a[i]--; b[i]--;
        addEdge(a[i], b[i]);
        
        edge e1, e2;
        e1.to = b[i]; e2.to = a[i];
        e1.cost = d[i]; e2.cost = d[i];
        e1.color = c[i]; e2.color = c[i];
        pre_G[a[i]].push_back(e1); pre_G[b[i]].push_back(e2);
    }


    make_netsukigi(0);
    preprocess(MAXN);

    int num = 0;
    rep(i,MAX_N){
        rep(j,G[i].size()){
            G[i][j].id = num;
            a[num] = i;
            b[num] = G[i][j].to;
            c[num] = G[i][j].color;
            d[num] = G[i][j].cost;
            num++;
        }
    } 

    init_euler_tour();


    rep(i,MAX_N){
        int sum = 0, num = 0;
        rep(j,euler_color[i].size()){
            int id = euler_color[i][j];
            euler_sum[i].push_back(sum);
            euler_num[i].push_back(num);
            if(euler_tour[id].second == 1){
                sum += euler_tour[id].first;
                num++;
            }else{
                sum -= euler_tour[id].first;
                num--;
            }
        }
        euler_sum[i].push_back(sum);
        euler_num[i].push_back(num);
    }



    rep(i,q){
        int x, y, uv[3];
        /*
        x = i / 25 + 1;
        y = 10000;
        uv[0] = (i / 5) % 5 + 1;
        uv[1] = i % 5 + 1;
        */
        cin >> x >> y >> uv[0] >> uv[1];
        uv[0]--; uv[1]--;
        uv[2] = LCASQRT(uv[0], uv[1]);
        int duv[3] = {};

        rep(j,3){
            duv[j] = dist[uv[j]];
            int ite = lower_bound(euler_color[x].begin(), euler_color[x].end(), place[uv[j]]) - euler_color[x].begin();
            duv[j] += euler_num[x][ite] * y - euler_sum[x][ite];
        }

        int ans = duv[0] + duv[1] - 2*duv[2];
        // cout << x << ' ' << y << ' ' << uv[0] << ' ' << uv[1] << ' ' << ans << endl;
        // cout << duv[0] << ' ' << duv[1] << ' ' << duv[2] << endl;
        cout << ans << endl;
    }

    return 0;
}


Measured memory_bytes: 67824