// Code By H~$~C

module main;

import core.stdc.stdlib, core.stdc.string;
import std.stdio, std.array, std.string, std.math, std.uni;
import std.algorithm, std.range, std.random, std.container;
import std.conv, std.typecons, std.functional;

immutable Maxn = 100005;
immutable LOG = 19;

int n, q;
Tuple!(int, int, int)[][Maxn] g, qry;
int[LOG][Maxn] par;
int[Maxn] depth, dist, D, ans;

void dfs1(int u, int fa) {
  depth[u] = depth[fa] + 1;
  par[u][0] = fa;
  for (int j = 1; j < LOG; ++j)
    par[u][j] = par[par[u][j - 1]][j - 1];
  foreach(pr; g[u]) {
    int v = pr[0], w = pr[2];
    if (v == fa) continue;
    dist[v] = dist[u] + w;
    dfs1(v, u);
  }
}
int get_lca(int u, int v) {
  if (depth[u] > depth[v]) swap(u, v);
  for (int j = LOG - 1; j >= 0; --j)
    if ((depth[v] - depth[u]) & (1 << j))
      v = par[v][j];
  if (u == v) return u;
  for (int j = LOG - 1; j >= 0; --j) {
    if (par[u][j] != par[v][j]) {
      u = par[u][j];
      v = par[v][j];
    }
  }
  return par[u][0];
}

int[Maxn] dis, cnt;
void dfs2(int u, int fa) {
  foreach(pr; g[u]) {
    int v = pr[0], c = pr[1], w = pr[2];
    if (v == fa) continue;
    dis[c] += w, cnt[c]++;
    dfs2(v, u);
    dis[c] -= w, cnt[c]--;
  }
  foreach(pr; qry[u]) {
    int c = pr[0], v = pr[1], id = pr[2];
    ans[id] += (D[id] * cnt[c] - dis[c]) * v;
  }
}

void solve(in int testcase) {
  n.read, q.read;
  foreach(i; 1 .. n) {
    int u, v, c, d;
    u.read, v.read, c.read, d.read;
    g[u] ~= tuple(v, c, d);
    g[v] ~= tuple(u, c, d);
  }
  dfs1(1, 0);
  foreach(i; 1 .. q + 1) {
    int u, v, c;
    c.read, D[i].read, u.read, v.read;
    int lca = get_lca(u, v);
    ans[i] = dist[u] + dist[v] - 2 * dist[lca];
    qry[u] ~= tuple(c, 1, i);
    qry[v] ~= tuple(c, 1, i);
    qry[lca] ~= tuple(c, -2, i);
  }
  dfs2(1, 0);
  
  foreach(i; ans[1 .. q + 1])
    writeln(i);
}

// ************************************************************

T reader(T)() { return readToken().to!T; }
void read(T)(ref T t) { t = reader!T; }
T[] readarray(T)() { return readln.splitter.map!(to!T).array; }
void chmax(T)(ref T a, T b) { a = max(a, b); }
void chmin(T)(ref T a, T b) { a = min(a, b); }
alias less = (a, b) => a < b;
alias greater = (a, b) => a > b;
T min_element(T)(in T[] a) { return a.element!less; }
T max_element(T)(in T[] a) { return a.element!greater; }
alias unique = uniq;

// constant or some variables
immutable int inf = 0x3f3f3f3f;
immutable long lnf = 0x3f3f3f3f3f3f3f3f;
immutable typeof(null) NULL = null;
string[] _tokens;

// functions
T element(alias pred, T)(in T[] a) {
  int pos = 0;
  for (int i = 1; i < cast(int)(a.length); ++i)
    if (binaryFun!pred(a[i], a[pos])) pos = i;
  return a[pos];
}
string readToken() {
  for (; _tokens.empty; ) {
    if (stdin.eof) return "";
    _tokens = readln.split;
  }
  auto token = _tokens.front;
  _tokens.popFront;
  return token;
}
int binary_bearch(alias pred, T)(in T[] as) {
  int l = -1, h = cast(int)(as.length), mid;
  for (; l + 1 < h; ) {
    mid = (l + h) >> 1;
    (unaryFun!pred(as[mid]) ? h : l) = mid;
  }
  return h;
}
int lower_bound(alias pred = less, T)(in T[] as, T val) {
  return as.binary_bearch!(a => a == val || pred(val, a));
}
int upper_bound(alias pred = less, T)(in T[] as, T val) {
  return as.binary_bearch!(a => pred(val, a));
}

void main(string[] args) {
  int tests = 1;
//  tests.read();
  foreach(test; 1 .. tests + 1) solve(test);
}
