#include <bits/stdc++.h>

#define rep(i, n) for (int i = 0; i < (n); i++)
#define repr(i, n) for (int i = (n) - 1; i >= 0; i--)

using namespace std;
using ll = long long;

struct HLD {
  vector<int> label, parent, head;
 
  HLD(const vector<vector<int>> &g) : label(g.size()), parent(g.size()), head(g.size()) {
    const int n = g.size();
    vector<int> size(n, 1);
    auto dfs = [&](auto dfs, int u, int p) -> void {
      for (int v : g[u]) if (v != p) {
        dfs(dfs, v, u);
        size[u] += size[v];
      }
    };
    dfs(dfs, 0, -1);
    int k = 0;
    auto dfs2 = [&](auto dfs, int u, int p, int h) -> void {
      label[u] = k++;
      head[u] = h;
      parent[u] = p;
      for (int v : g[u]) if (v != p && size[v] * 2 >  size[u]) dfs(dfs, v, u, h);
      for (int v : g[u]) if (v != p && size[v] * 2 <= size[u]) dfs(dfs, v, u, v);
    };
    dfs2(dfs2, 0, -1, 0);
  }
 
  int lca(int u, int v) {
    for (;;) {
      if (label[u] > label[v]) swap(u, v);
      if (head[u] == head[v]) return u;
      v = parent[head[v]];
    }
  }
 
  template<class F> void each(int u, int v, F f) {
    for (;;) {
      if (label[u] > label[v]) swap(u, v);
      if (head[u] == head[v]) {
        f(label[u], label[v]);
        return;
      }
      f(label[head[v]], label[v]);
      v = parent[head[v]];
    }
  }
 
  template<class F> void each_edge(int u, int v, F f) {
    for (;;) {
      if (label[u] > label[v]) swap(u, v);
      if (head[u] == head[v]) {
        if (u != v) f(label[u] + 1, label[v]);
        return;
      }
      f(label[head[v]], label[v]);
      v = parent[head[v]];
    }
  }
 
  int operator[](int u) {
    return label[u];
  };
};

// T: ring
template<class T>
struct wavelet_matrix {
  int H;
  vector<vector<int>> cnt;
  vector<vector<T>> sum;
  struct value {
    int x, y;
    T v;
  };
  vector<int> xs;
  vector<int> ys;
  vector<value> vs;

  void insert(int x, int y, T v) {
    xs.push_back(x);
    ys.push_back(y);
    vs.push_back((value){x, y, v});
  }

  void build() {
    const int n = xs.size();
    if (n == 0) return;
    sort(xs.begin(), xs.end());
    sort(ys.begin(), ys.end());
    ys.erase(unique(ys.begin(), ys.end()), ys.end());
    sort(vs.begin(), vs.end(), [](value a, value b) { return a.x < b.x; });
    for (int i = 0; i < n; i++) {
      vs[i].y = lower_bound(ys.begin(), ys.end(), vs[i].y) - ys.begin();
    }
    H = 0;
    while ((1 << H) < ys.size()) H++;
    cnt.assign(H, vector<int>(n + 1));
    sum.assign(H+1, vector<T>(n + 1));
    auto dfs = [&](auto dfs, int l, int r, int h) -> void {
      if (r - l == 0) return;
      for (int i = l; i < r; i++) {
        sum[h][i + 1] = sum[h][i] + vs[i].v;
      }
      if (h == H) return;
      for (int i = l; i < r; i++) {
        cnt[h][i + 1] = cnt[h][i] + (~vs[i].y >> (H - 1 - h) & 1);
      }
      int m = stable_partition(vs.begin() + l, vs.begin() + r, [&](value x) {
        return ~x.y >> (H - 1 - h) & 1;
      }) - vs.begin();
      dfs(dfs, l, m, h + 1);
      dfs(dfs, m, r, h + 1);
    };
    dfs(dfs, 0, n, 0);
  }

  // [l,r) * [b,t)
  T query(int l, int r, int b, int t) {
    const int n = xs.size();
    l = lower_bound(xs.begin(), xs.end(), l) - xs.begin();
    r = lower_bound(xs.begin(), xs.end(), r) - xs.begin();
    b = lower_bound(ys.begin(), ys.end(), b) - ys.begin();
    t = lower_bound(ys.begin(), ys.end(), t) - ys.begin();
    auto dfs = [&](auto dfs, int l, int r, int b, int t, int ll, int rr, int bb, int tt, int h) -> T {
      if (r - l == 0 || t - b == 0) return T();
      if (tt <= b || t <= bb) return T();
      if (b <= bb && tt <= t) return sum[h][r] - sum[h][l];
      int mm = ll + cnt[h][rr] - cnt[h][ll];
      T vl = dfs(dfs, ll + cnt[h][l] - cnt[h][ll], ll + cnt[h][r] - cnt[h][ll], b, t, ll, mm, bb, (bb + tt) / 2, h + 1);
      T vr = dfs(dfs, l + cnt[h][rr] - cnt[h][l], r + cnt[h][rr] - cnt[h][r], b, t, mm, rr, (bb + tt) / 2, tt, h + 1);
      return vl + vr;
    };
    return dfs(dfs, l, r, b, t, 0, n, 0, 1<<H, 0);
  }
};

int main() {
  cin.tie(nullptr);
  ios::sync_with_stdio(false);
  int n, q;
  cin >> n >> q;
  vector<vector<int>> g(n);
  struct edge {
    int v, c, w;
  };
  vector<vector<edge>> g2(n);
  rep(i, n-1) {
    int u, v, c, w;
    cin >> u >> v >> c >> w;
    u--; v--;
    g[u].push_back(v);
    g[v].push_back(u);
    g2[u].push_back((edge){v, c, w});
    g2[v].push_back((edge){u, c, w});
  }
  HLD hld(g);
  vector<int> ws(n);
  vector<int> cs(n);
  auto dfs = [&](auto dfs, int u, int p) -> void {
    for (edge e : g2[u]) {
      if (e.v == p) continue;
      ws[e.v] = e.w;
      cs[e.v] = e.c;
      dfs(dfs, e.v, u);
    }
  };
  dfs(dfs, 0, -1);
  wavelet_matrix<int> wm1;
  wavelet_matrix<ll> wm2;
  rep(i, n) {
    wm1.insert(hld[i], cs[i], 1);
    wm2.insert(hld[i], cs[i], ws[i]);
  }
  wm1.build();
  wm2.build();
  while (q--) {
    int x, y, u, v;
    cin >> x >> y >> u >> v;
    u--;
    v--;
    ll ans = 0;
    hld.each_edge(u, v, [&](int l, int r) {
      r++;
      ans += wm2.query(l, r, 0, 1<<17);
      ans -= wm2.query(l, r, x, x+1);
      ans += wm1.query(l, r, x, x+1) * y;
    });
    cout << ans << '\n';
  }
}


Measured memory_bytes: 81420