#include <iostream>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#define MAX_PARENT 20
using namespace std;

struct Edge {
  int dest;
  int color;
  int dist;
  Edge(int dest, int color, int dist) : dest(dest), color(color), dist(dist) {}
};

struct Node {
  vector<Edge> edges;
  unordered_map<int, int> edgeColorCount;
  unordered_map<int, int> edgeColorDist;
  int dist = 0;
  int depth = 0;
  vector<int> parent;
  Node() { parent.resize(MAX_PARENT, -1); }
};

void addDepth(vector<Node>& node, vector<bool>& visited, int nodeNum) {
  for (Edge& edge : node[nodeNum].edges) {
    if (!visited[edge.dest]) {
      visited[edge.dest] = true;
      node[edge.dest].parent[0] = nodeNum;
      node[edge.dest].depth = node[nodeNum].depth + 1;
      node[edge.dest].dist = node[nodeNum].dist + edge.dist;
      addDepth(node, visited, edge.dest);
      visited[edge.dest] = false;
    }
  }
}

void dfs(vector<Node>& node, vector<bool>& visited,
         unordered_map<int, unordered_set<int>>& query, int nodeNum,
         unordered_map<int, int>& edgeColorCount,
         unordered_map<int, int>& edgeColorDist) {
  for (Edge& edge : node[nodeNum].edges) {
    if (!visited[edge.dest]) {
      visited[edge.dest] = true;
      edgeColorCount[edge.color]++;
      edgeColorDist[edge.color] += edge.dist;
      if (query.find(edge.dest) != query.end()) {
        for (int color : query[edge.dest]) {
          node[edge.dest].edgeColorCount[color] = edgeColorCount[color];
          node[edge.dest].edgeColorDist[color] = edgeColorDist[color];
        }
      }
      dfs(node, visited, query, edge.dest, edgeColorCount, edgeColorDist);
      visited[edge.dest] = false;
      edgeColorCount[edge.color]--;
      edgeColorDist[edge.color] -= edge.dist;
    }
  }
}

int solveLCA(vector<Node>& nodes, int u, int v) {
  if (nodes[u].depth > nodes[v].depth) swap(u, v);

  for (int k = 0; k < MAX_PARENT; ++k) {
    if ((nodes[v].depth - nodes[u].depth) >> k & 1) {
      v = nodes[v].parent[k];
    }
  }
  if (u == v) return u;
  for (int k = MAX_PARENT - 1; k >= 0; --k) {
    if (nodes[u].parent[k] != nodes[v].parent[k]) {
      u = nodes[u].parent[k];
      v = nodes[v].parent[k];
    }
  }
  return nodes[u].parent[0];
}

int solve(vector<Node>& nodes, int x, int y, int u, int v, int lca) {
  int dist = nodes[u].dist + nodes[v].dist - nodes[lca].dist * 2;
  int colorCount = nodes[u].edgeColorCount[x] + nodes[v].edgeColorCount[x] -
                   nodes[lca].edgeColorCount[x] * 2;
  int colorDist = nodes[u].edgeColorDist[x] + nodes[v].edgeColorDist[x] -
                  nodes[lca].edgeColorDist[x] * 2;
  return dist - colorDist + colorCount * y;
}

int main() {
  int n, q;
  cin >> n >> q;
  vector<Node> nodes(n);
  for (int i = 0; i < n - 1; i++) {
    int a, b, c, d;
    cin >> a >> b >> c >> d;
    a--, b--, c--;
    nodes[a].edges.push_back(Edge(b, c, d));
    nodes[b].edges.push_back(Edge(a, c, d));
  }
  vector<bool> visited(n, false);
  visited[0] = true;
  addDepth(nodes, visited, 0);
  for (int k = 1; k < MAX_PARENT; ++k) {
    for (Node& node : nodes) {
      if (node.parent[k - 1] < 0)
        node.parent[k] = -1;
      else
        node.parent[k] = nodes[node.parent[k - 1]].parent[k - 1];
    }
  }

  vector<tuple<int, int, int, int, int>> questions;
  unordered_map<int, unordered_set<int>> query;
  for (int i = 0; i < q; i++) {
    int x, y, u, v, lca;
    cin >> x >> y >> u >> v;
    x--, u--, v--;
    lca = solveLCA(nodes, u, v);
    questions.push_back(make_tuple(x, y, u, v, lca));
    query[u].insert(x), query[v].insert(x), query[lca].insert(x);
  }
  
  unordered_map<int, int> edgeColorCount;
  unordered_map<int, int> edgeColorDist;
  visited[0] = true;
  dfs(nodes, visited, query, 0, edgeColorCount, edgeColorDist);

  for (auto& question : questions) {
    int x, y, u, v, lca;
    tie(x, y, u, v, lca) = question;
    cout << solve(nodes, x, y, u, v, lca) << endl;
  }
  return 0;
}


Measured memory_bytes: 85576