#include<bits/stdc++.h>
#include<string.h>
 
typedef long long int ll;
#define all(x) (x).begin(), (x).end()
 
using namespace std;

int nxt() {
    int x;
    cin >> x;
    return x;
}

ll nxtl(){
    ll x;
    cin>>x;
    return x;
}
 
void SieveOfEratosthenes(int n,vector <int> &primes) 
{ 
    // Create a boolean array "prime[0..n]" and initialize 
    // all entries it as true. A value in prime[i] will 
    // finally be false if i is Not a prime, else true. 
    bool prime[n+1]; 
    memset(prime, true, sizeof(prime)); 
  
    for (int p=2; p*p<=n; p++) 
    { 
        // If prime[p] is not changed, then it is a prime 
        if (prime[p] == true) 
        { 
            // Update all multiples of p greater than or  
            // equal to the square of it 
            // numbers which are multiple of p and are 
            // less than p^2 are already been marked.  
            for (int i=p*p; i<=n; i += p) 
                prime[i] = false; 
        } 
    } 
  
    // Print all prime numbers 
    for (int p=2; p<=n; p++) 
       if (prime[p]) 
          primes.push_back(p);
} 
 
ll max(ll a,ll b)
{
    if(a>b)
        return a;
    return b;
}
 
ll power(ll x, ll y,ll mod) 
{ 
    ll temp; 
    if( y == 0) 
        return 1; 
    temp = power(x, y/2,mod); 
    if (y%2 == 0) 
        return (temp*temp)%mod; 
    else
        return (((x*temp)%mod)*temp)%mod; 
}

vector <vector <int> > g;

vector <int> parent;
vector <int> depth;
void dfs2(int s,int depth2,vector <bool> &visited);


// Pre-processing to calculate values of memo[][] 
void dfs(int u, int p, int **memo, int *lev, int log, vector<int> *g) 
{ 
    // Using recursion formula to calculate 
    // the values of memo[][] 
    memo[u][0] = p; 
    for (int i = 1; i <= log; i++) 
        memo[u][i] = memo[memo[u][i - 1]][i - 1]; 
    for (int v : g[u]) 
    { 
        if (v != p) 
        { 
            lev[v] = lev[u] + 1; 
            dfs(v, u, memo, lev, log, g); 
        } 
    } 
} 
  
// Function to return the LCA of nodes u and v 
int lca(int u, int v, int log, int *lev, int **memo) 
{ 
    // The node which is present farthest 
    // from the root node is taken as u 
    // If v is farther from root node 
    // then swap the two 
    if (lev[u] < lev[v]) 
        swap(u, v); 
  
    // Finding the ancestor of u 
    // which is at same level as v 
    for (int i = log; i >= 0; i--) 
        if ((lev[u] - pow(2, i)) >= lev[v]) 
            u = memo[u][i]; 
  
    // If v is the ancestor of u 
    // then v is the LCA of u and v 
    if (u == v) 
        return u; 
  
    // Finding the node closest to the root which is 
    // not the common ancestor of u and v i.e. a node 
    // x such that x is not the common ancestor of u 
    // and v but memo[x][0] is 
    for (int i = log; i >= 0; i--) 
    { 
        if (memo[u][i] != memo[v][i]) 
        { 
            u = memo[u][i]; 
            v = memo[v][i]; 
        } 
    } 
  
    // Returning the first ancestor 
    // of above found node 
    return memo[u][0]; 
}

void dfs2(int s,vector <bool> &visited,vector <int> &euler_edge,vector <int> &euler_vertex,map <pair<int,int>,int> &edges2,vector <int> &path_sum,int sum,vector <vector <int> > &edges);
void cal(int index,vector <vector<int> > &colors,int x,int &num,int &sum,vector <vector<int> > &colors_prefix_sum,vector <vector<int> > &colors_prefix_count);

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    int n=nxt();int q=nxt();
    vector <vector <int> > edges;
    map <pair<int,int>,int> edges2;
    vector <int> r(4);
    edges.resize(n+1,r);
    vector <int> row;
    g.resize(n+1,row);
    vector<int> g2[n + 1]; 
    for(int i=1;i<=n-1;i++)
    {
        int u=nxt(),v=nxt(),c=nxt(),d=nxt();
        g[u].push_back(v);
        g[v].push_back(u);
        g2[u].push_back(v);
        g2[v].push_back(u);
        edges[i][0]=u;
        edges[i][1]=v;
        edges[i][2]=c;
        edges[i][3]=d;
        edges2[{u,v}]=i;
        edges2[{v,u}]=i;
       
    }

    int log = (int)ceil(log2(n)); 
    int **memo = new int *[n + 1]; 
    for (int i = 0; i < n + 1; i++) 
        memo[i] = new int[log + 1]; 
  
    // Stores the level of each node 
    int *lev = new int[n + 1]; 
  
    // Initialising memo values with -1 
    for (int i = 0; i <= n; i++) 
        memset(memo[i], -1, sizeof memo[i]); 

    dfs(1, 1, memo, lev, log, g2);
    
    vector <int> path_sum(n+1);
    vector <bool> visited;
    visited.resize(n+1,0);
    vector <int> euler_edge;
    vector <int> euler_vertex;
    dfs2(1,visited,euler_edge,euler_vertex,edges2,path_sum,0,edges);
    int k=euler_edge.size();
    vector <vector<int> > colors;
    colors.resize(n,row);
    vector <vector<int> > colors_prefix_sum;
    colors_prefix_sum.resize(n,row);
    vector <vector<int> > colors_prefix_count;
    colors_prefix_count.resize(n,row);
    vector <int> vertex_index(n+1);
    vertex_index[1]=-1;
    for(int i=0;i<k;i++)
    {
        if(euler_vertex[i]>0)
            vertex_index[euler_vertex[i]]=i;
        colors[edges[abs(euler_edge[i])][2]].push_back(i);
    }
    for(int i=1;i<=n-1;i++)
    {
        for(int j=0;j<colors[i].size();j++)
        {
            if(j==0)
            {
                colors_prefix_count[i].push_back(1);
                colors_prefix_sum[i].push_back(edges[euler_edge[colors[i][j]]][3]);
            }
            else
            {
                if(euler_edge[colors[i][j]]>0)
                colors_prefix_count[i].push_back(colors_prefix_count[i][j-1]+1);
                else
                  colors_prefix_count[i].push_back(colors_prefix_count[i][j-1]-1); 
                if(euler_edge[colors[i][j]]>0)
                colors_prefix_sum[i].push_back(colors_prefix_sum[i][j-1]+edges[euler_edge[colors[i][j]]][3]);
                else
                    colors_prefix_sum[i].push_back(colors_prefix_sum[i][j-1]-edges[-euler_edge[colors[i][j]]][3]);
            }
        }
    }
    while(q--)
    {
        int x=nxt(),y=nxt(),u=nxt(),v=nxt();
        int w=lca(u,v,log,lev,memo);
        int u_sum=path_sum[u];
        int v_sum=path_sum[v];
        int w_sum=path_sum[w];
        int num=0,sum=0;
        cal(vertex_index[u],colors,x,num,sum,colors_prefix_sum,colors_prefix_count);
        u_sum+=(y*num-sum);

        num=0;sum=0;
        cal(vertex_index[v],colors,x,num,sum,colors_prefix_sum,colors_prefix_count);
        v_sum+=(y*num-sum);

        num=0;sum=0;
        cal(vertex_index[w],colors,x,num,sum,colors_prefix_sum,colors_prefix_count);
        w_sum+=(y*num-sum);

        cout<<u_sum+v_sum-2*(w_sum)<<"\n";
        

    }
    
    
    return 0;   
}

void dfs2(int s,vector <bool> &visited,vector <int> &euler_edge,vector <int> &euler_vertex,map <pair<int,int>,int> &edges2,vector <int> &path_sum,int sum,vector <vector <int> > &edges)
{
    visited[s]=1;
    path_sum[s]=sum;
    for(auto i:g[s])
    {
        if(!visited[i])
        {
            euler_edge.push_back(edges2[{s,i}]);
            euler_vertex.push_back(i);
            dfs2(i,visited,euler_edge,euler_vertex,edges2,path_sum,sum+edges[edges2[{s,i}]][3],edges);
            euler_edge.push_back(-edges2[{s,i}]);
            euler_vertex.push_back(-i);
        }
    }
}

void cal(int index,vector <vector<int> > &colors,int x,int &num,int &sum,vector <vector<int> > &colors_prefix_sum,vector <vector<int> > &colors_prefix_count)
{
    int test=-1;
    int l=0,r=colors[x].size()-1;
    while(l<=r)
    {
        int mid=(l+r)/2;
        if(colors[x][mid]<=index)
        {
            test=mid;
            l=mid+1;
        }
        else
            r=mid-1;
    }
    if(test!=-1)
    {
        num=colors_prefix_count[x][test];
        sum=colors_prefix_sum[x][test];
    }
}


 
 


Measured memory_bytes: 64236