#include <iostream>
#include <vector>
#include <map>

using namespace std;
#ifdef __DEBUG__
    void debug_out() { cerr << endl; } 
    template <typename Head, typename... Tail>
    void debug_out(Head H, Tail... T) {cerr << " " << H; debug_out(T...);}
    #define debug(...) cerr << "[" << #__VA_ARGS__ << "]:", debug_out(__VA_ARGS__)
#else
    #define debug(...) 
#endif

using ll = long long int;
using pii = pair<int, int>;
#define ROOT 0

inline void fast_io() { ios_base::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); };
template<typename T, typename S> inline ostream& operator<<(ostream& os, const pair<T, S> p) { cout << "[" << p.first << ";" << p.second << "]"; return os; }
template<typename T> inline ostream& operator<<(ostream& os, const vector<T>& v) { for (auto el : v) cout << el << " "; return os; }

int N, Q;
vector<int> _dist;
vector<vector<int>> G;
map<pii, pii> edge;
struct query{int x, y, u, v;};
struct query_node{int x, y, cof, idx;};
vector<query> qs;
vector<vector<query_node> > qs_node;
vector<int> ans;

inline void input(){
    fast_io();
    cin >> N >> Q;
    _dist.assign(N, 0);
    G.resize(N);
    for (int i = 0; i < N-1; i++)
    {
        int a,b,c,d;
        cin >> a >> b >> c >> d;
        a--, b--;
        G[a].push_back(b);
        G[b].push_back(a);
        edge[make_pair(a,b)] = make_pair(c,d);
        edge[make_pair(b,a)] = make_pair(c,d);
    }
    qs.resize(Q);
    for (int q = 0; q < Q; q++)
    {
        int x, y, u, v;
        cin >> x >> y >> u >> v;
        u--, v--;
        qs[q] = query{x,y,u,v};
    }
}

template< typename G >
struct LCA {
  const int LOG;
  vector< int > dep;
  const G &g;
  vector< vector< int > > table;

  LCA(const G &g) : g(g), dep(g.size()), LOG(32 - __builtin_clz(g.size())) {
    table.assign(LOG, vector< int >(g.size(), -1));
  }

  void dfs(int idx, int par, int d) {
    table[0][idx] = par;
    dep[idx] = d;
    for(auto &to : g[idx]) {
      if(to != par) dfs(to, idx, d + 1);
    }
  }

  void build() {
    dfs(0, -1, 0);
    for(int k = 0; k + 1 < LOG; k++) {
      for(int i = 0; i < table[k].size(); i++) {
        if(table[k][i] == -1) table[k + 1][i] = -1;
        else table[k + 1][i] = table[k][table[k][i]];
      }
    }
  }

  int query(int u, int v) {
    if(dep[u] > dep[v]) swap(u, v);
    for(int i = LOG - 1; i >= 0; i--) {
      if(((dep[v] - dep[u]) >> i) & 1) v = table[i][v];
    }
    if(u == v) return u;
    for(int i = LOG - 1; i >= 0; i--) {
      if(table[i][u] != table[i][v]) {
        u = table[i][u];
        v = table[i][v];
      }
    }
    return table[0][u];
  }
};

void dfs_dist(int u, int p = -1, int d = 0){
    _dist[u] = d;
    for(auto v:G[u]){
        if(v == p) continue;
        dfs_dist(v, u, d + edge[make_pair(u, v)].second);
    }
    return ;
}

vector<int> sum, cnt;
vector<query> node;
void dfs_query(int u, int p = -1){
    for(auto q:qs_node[u]){
        ans[q.idx] += q.cof*(q.y*cnt[q.x]-sum[q.x]);
    }
    for(auto v:G[u]){
        if(v == p) continue;
        int col, di;
        tie(col, di) = edge[make_pair(u, v)];
        sum[col] += di;
        cnt[col]++; 
        dfs_query(v, u);
        sum[col] -= di;
        cnt[col]--; 
    }
}

inline int solve(){
    sum.resize(N);
    cnt.resize(N);
    qs_node.resize(N);
    ans.resize(Q);
    dfs_dist(ROOT);

    LCA< vector<vector<int>> > lca(G);
    lca.build();
    for (int i = 0; i < Q; i++)
    {
        int u, v, x, y;
        u = qs[i].u;
        v = qs[i].v;
        x = qs[i].x;
        y = qs[i].y;

        int lca_uv = lca.query(u, v);
        ans[i] = _dist[u] + _dist[v] - 2*_dist[lca_uv];
        qs_node[u].push_back(query_node{x, y, 1, i});
        qs_node[v].push_back(query_node{x, y, 1, i});
        qs_node[lca_uv].push_back(query_node{x, y, -2, i});        
    }
    dfs_query(ROOT);
    for (int i = 0; i < Q; i++)
    {
        cout << ans[i] << "\n";
    }
    
    return 0;
}   

// 木の更新問題はHL分解で解く！実家！
int main()
{
    input();
    solve();
    return 0;
}


Measured memory_bytes: 48396