#include <algorithm>
#include <cmath>
#include <functional>
#include <iomanip>
#include <iostream>
#include <limits>
#include <map>
#include <queue>
#include <set>
#include <tuple>
#include <typeinfo>
#include <vector>

using namespace std;

#define rep(i, n) for (int64_t i = 0; i < (int64_t)(n); i++)
#define irep(i, n) for (int64_t i = 0; i <= (int64_t)(n); i++)
#define rrep(i, n) for (int64_t i = (n)-1; i >= 0; i--)
#define rirep(i, n) for (int64_t i = n; i >= 0; i--)

template <typename T>
class SegmentTree {
  const T unit;
  const function<T(const T&, const T&)> op;
  vector<T> container;

 public:
  template <typename Op>
  SegmentTree(int size, const T& identity, const Op& operation)
      : unit(identity), op(operation), container(msb(size * 2 - 1)) {
    fill(container.begin(), container.end(), unit);
  }
  void update(size_t index, T value) {
    int n = container.size() / 2;
    container[index + n] = value;

    int node = (index + n) >> 1;
    while (node > 0) {
      container[node] = op(container[node << 1], container[(node << 1) + 1]);
      node >>= 1;
    }
  }
  T find(size_t s, size_t t) {
    if (s >= t) {
      return unit;
    }
    return find_inner(s, t, 0, container.size() / 2);
  }

 private:
  T find_inner(size_t s, size_t t, size_t lb, size_t ub) {
    if (s == lb && t == ub) {
      int n = container.size() / 2;
      return container[lca(n + s, n + t - 1)];
    }

    T result = unit;
    size_t mid = (lb + ub) / 2;
    if (mid > s) {
      result = op(result, find_inner(s, min(mid, t), lb, mid));
    }
    if (mid < t) {
      result = op(result, find_inner(max(s, mid), t, mid, ub));
    }

    return result;
  }
  int lca(int n0, int n1) {
    int a = n0 ^ n1;
    return n0 / msb(a);
  }
  int msb(int x) {
    x |= x >> 1;
    x |= x >> 2;
    x |= x >> 4;
    x |= x >> 8;
    x |= x >> 16;

    return x + 1;
  }
};

using E = tuple<int, int, int>;
vector<vector<E>> edge;

vector<bool> is_visited;
vector<int> depth;
vector<int> tour;
vector<vector<int>> order;
vector<vector<int>> to;
vector<int> dist;
vector<vector<int>> dist_col;
vector<vector<int>> cnt;

void euler_tour(int node, int w, int col, int dep) {
  is_visited[node] = true;
  depth[node] = dep;
  order[node].push_back(tour.size());
  if (col >= 0) {
    to[col].push_back(tour.size());
    dist_col[col].push_back(w);
    cnt[col].push_back(1);
  }
  dist.push_back(w);
  tour.push_back(node);
  for (E e : edge[node]) {
    int a, c, d;
    tie(a, c, d) = e;
    if (!is_visited[a]) {
      euler_tour(a, d, c, dep + 1);
      order[node].push_back(tour.size());
      to[c].push_back(tour.size());
      dist_col[c].push_back(-d);
      cnt[c].push_back(-1);
      dist.push_back(-d);
      tour.push_back(node);
    }
  }
}

int solve(int node, int col, int len) {
  int cnum = upper_bound(to[col].begin(), to[col].end(), order[node].front()) -
             to[col].begin() - 1;
  int d = dist[order[node].front()];
  int cd = dist_col[col][cnum];
  int x = cnt[col][cnum];
  int result = d - cd + len * x;
  //*
  cerr << " node: " << node << "\n";
  cerr << " number of directed edge with color " << col << " : " << cnum
       << "\n";
  cerr << " number of undirected edge with color " << col << " : " << x << "\n";
  cerr << " distance (0, " << node << ") :" << d << "\n";
  cerr << " cweight :" << cd << "\n\n";
  cerr << " result: " << result << endl;
  //*/
  return result;
}

int main() {
  int N, Q;
  cin >> N >> Q;
  edge.resize(N);

  rep(i, N - 1) {
    int a, b, c, d;
    cin >> a >> b >> c >> d;
    a--;
    b--;
    c--;
    edge[a].push_back(E(b, c, d));
    edge[b].push_back(E(a, c, d));
  }

  depth.resize(N);
  is_visited.resize(N, false);
  order.resize(N);
  to.resize(N - 1, vector<int>(1, 0));
  dist_col.resize(N - 1, vector<int>(1, 0));
  cnt.resize(N - 1, vector<int>(1, 0));
  euler_tour(0, 0, -1, 0);

  rep(i, N - 1) {
    const int k = dist_col[i].size() - 1;
    rep(j, dist_col[i].size() - 1) { dist_col[i][j + 1] += dist_col[i][j]; }
    rep(j, cnt[i].size() - 1) { cnt[i][j + 1] += cnt[i][j]; }
  }
  rep(i, tour.size() - 1) { dist[i + 1] += dist[i]; }

  using P = pair<int, int>;
  SegmentTree<P> seg(tour.size(), P(N, -1),
                     [](const P& lh, const P& rh) { return min(lh, rh); });
  rep(i, tour.size()) { seg.update(i, P(depth[tour[i]], i)); }

  /* debug
  cerr << "tour: ";
  for (int t : tour) {
    cerr << " " << t;
  }
  cerr << "\n";

  cerr << "dist_col: \n";
  for (const auto& ds : dist_col) {
    for (const auto& d : ds) {
      cerr << " " << d;
    }
    cerr << "\n";
  }
  cerr << "\n";

  cerr << "cnt: \n";
  for (const auto& ds : cnt) {
    for (const auto& d : ds) {
      cerr << " " << d;
    }
    cerr << "\n";
  }
  cerr << "\n";

  cerr << "to: \n";
  for (const auto& ds : to) {
    for (const auto& d : ds) {
      cerr << " " << d;
    }
    cerr << "\n";
  }
  cerr << "\n";
  //*/

  rep(i, Q) {
    int x, y, u, v;
    cin >> x >> y >> u >> v;
    x--;
    u--;
    v--;

    int l = order[u].front(), r = order[v].front();
    if (l > r) {
      swap(l, r);
    }
    int lca;
    tie(ignore, lca) = seg.find(l, r + 1);

    cerr << x << " " << y << " " << u << " " << v << "\n";
    cout << solve(u, x, y) + solve(v, x, y) - 2 * solve(tour[lca], x, y)
         << "\n";
  }

  return 0;
}

Measured memory_bytes: 43464