#include<bits/stdc++.h>
using namespace std;

using Size = int;
using Vertex = int;
using Weight = long long;
struct Edge {Vertex from, to; Weight color, weight;};
using Graph = std::vector<std::vector<Edge>>;

class CentroidDecomposition {
 public:
  map<Vertex, map<Weight, vector<Edge>>> chain;
  vector<Weight> cost;

  CentroidDecomposition(const Graph& G, Vertex root) : cost(G.size()), parent(G.size(), NIL), depth(G.size(), 0), subsize(G.size(), 1), head(G.size()) {
    std::function<Size(Vertex)> dfs = [&](Vertex cur) {
      for(const auto& e: G[cur]) if(e.to != parent[cur]) {
        depth[e.to] = depth[cur] + 1;
        parent[e.to] = cur;
        subsize[cur] += dfs(e.to);
      }
      return subsize[cur];
    };
    std::function<void(Vertex)> build = [&](Vertex cur) {
      Vertex nex = NIL;
      Size size = 0;
      for(const auto& e: G[cur]) if(e.to != parent[cur]) if(chmax(size, subsize[e.to]) == subsize[e.to]) nex = e.to;
      for(const auto& e: G[cur]) if(e.to != parent[cur]) {
        if(e.to == nex) head[e.to] = head[cur];
        else            head[e.to] = e.to;
        auto c = e;
        if(!chain[head[e.to]][e.color].empty()) c.weight += chain[head[e.to]][e.color].back().weight;
        chain[head[e.to]][e.color].emplace_back(c);
        cost[e.to] += cost[cur] + e.weight;
        build(e.to);
      }
    };
    dfs(root);
    build(head[root] = root);
  }
  Vertex lca(Vertex u, Vertex v) const {
    while(head[u] != head[v]) {
      if(depth[head[u]] > depth[head[v]]) std::swap(u, v);
      v = parent[head[v]];
    }
    return depth[u] < depth[v] ? u : v;
  }

  Vertex bsearch(const vector<Edge>& chain, Vertex v) {
    int l=0, h=chain.size();
    while(l+2 <= h) {
      auto m = (l + h) / 2;
      auto e = chain[m];
      if(depth[e.to] <= depth[v]) l = m;
      else                        h = m;
    }
    return l;
  }
  Weight query(Weight x, Weight y, Vertex u, Vertex v) {
    auto d = cost[u] + cost[v] - cost[lca(u, v)];
    while(head[u] != head[v]) {
      if(depth[head[u]] > depth[head[v]]) swap(u, v);
      if(!chain[head[v]][x].empty()) {
        auto k = bsearch(chain[head[v]][x], v);
        auto e = chain[head[v]][x][k];
        if(depth[e.from] < depth[v]) {
          d -= e.weight;
          d += (1+k) * y;
        }
      }
      v = parent[head[v]];
    }
    if(depth[u] > depth[v]) swap(u, v);
    if(!chain[head[v]][x].empty()) {
      auto k = bsearch(chain[head[v]][x], v);
      auto e = chain[head[v]][x][k];
      if(depth[e.from] < depth[v]) {
        d -= e.weight;
        d += (1+k) * y;
      }
    }
    d -= cost[u];
    if(!chain[head[u]][x].empty()) {
      auto k = bsearch(chain[head[u]][x], u);
      auto e = chain[head[u]][x][k];
      if(depth[e.from] < depth[u]) {
        d += cost[u];
        d -= cost[u] - e.weight + (1+k) * y;
      }
    }
    return d;
  }
  void debug() {
    for(auto v=0;v<depth.size();++v){
      cout<<v<<endl;
      cout<<"  p: "<<parent[v]<<endl;
      cout<<"  h: "<<head[v]<<endl;
      cout<<"  c: "<<cost[v]<<endl;
    }
    for(auto v=0;v<depth.size();++v)if(head[v]==v){
      cout<<v<<endl;
      for(auto c: chain[v]){
        cout<<"  color="<<c.first;
        for(auto e: c.second) cout<<" "<<e.from<<"-"<<e.to<<";"<<e.weight;
        cout<<endl;
      }
    }
    cout<<endl<<endl;
  }

 private:
  inline Size position(Vertex v) {return depth[v] - depth[head[v]];}
  template<typename T> inline T chmax(T& l, const T& r) {return l = std::max(l, r);};
  const Size NIL = -1;
  std::vector<Vertex> head, parent;
  std::vector<Size> depth, subsize;
};

int main() {
  int N, Q;
  cin >> N >> Q;

  Graph G(N+1);
  for(auto i=0; i<N-1; ++i) {
    int a, b, c, d;
    cin >> a >> b >> c >> d;
    G[a].push_back({a,b,c,d});
    G[b].push_back({b,a,c,d});
  }

  CentroidDecomposition T(G, 1);
//   T.debug();

  for(auto i=0; i<Q; ++i) {
    int x, y, u, v;
    cin >> x >> y >> u >> v;
    cout << T.query(x, y, u, v) << endl;
  }
}


Measured memory_bytes: 69376