#include <bits/stdc++.h>

using namespace std;

const int OO = 1e9;
const double EPS = 1e-9;

#define ndl cout << '\n'
#define sz(v) int(v.size())
#define pb push_back
#define mp make_pair
#define fs first
#define sc second
#define present(a, x) (a.find(x) != a.end())
#ifdef LOCAL
#define db(...) ({cout << "> Line " << __LINE__  \
		<< ": "; _db(#__VA_ARGS__, __VA_ARGS__);})
#else
#define db(...) true
#endif

template<class T>
void _db(const char *dbStr, T e) {
	cout << dbStr << " = " << e << endl;
}
template<class T, class... L>
void _db(const char *dbStr, T e, L... r) {
  while(*dbStr != ',') cout << *dbStr++;
  cout << " = " << e << ','; _db(dbStr + 1, r...);
}
template<class S, class T>
ostream& operator<<(ostream& o, const map<S, T>& v) {
	o << "["; int i = 0;
	for (const pair<S, T>& pr : v) o << (!i++ ? "" : ", ") << "{"
	<< pr.fs << " : " << pr.sc << "}"; return o << "]";
}
template<template <class, class...> class S, class T, class... L>
ostream& operator<<(ostream& o, const S<T, L...>& v) {
	o << "["; int i = 0;
	for (const auto& e : v) o << (!i++ ? "" : ", ") << e;
	return o << "]";
}
template<class S, class T>
ostream& operator<<(ostream& o, const pair<S, T>& pr) {
	return o << "(" << pr.fs << ", " << pr.sc << ")";
}
ostream& operator<<(ostream& o, const string& s) {
	for (const char& c : s) o << c;
	return o;
}

template<class T> using V = vector<T>;
template<class T> using VV = V<V<T>>;
template<class T> using VVV = VV<V<T>>;
using ll = long long;
using pii = pair<int, int>;
using vi = V<int>;
using vii = V<pii>;
using vvi = VV<int>;
using mii = map<int, int>;
using umii = unordered_map<int, int>;
using si = set<int>;
using usi = unordered_set<int>;

int N, Q;
V<V<pair<int, pii>>> adj;	// (v, (c, d))
vi D, E, W;
V<V<pair<int, pair<int, pii>>>> nodeQuery; // (ID, (c, (y, coef.)))
vi ans;

#define LOG_TWO_N 25

struct SparseTable {
	vi A;
	vvi SpT;
	vvi mnIdx;
	SparseTable(const vi& _A) {
		A = _A;
		int n = A.size();
		SpT.assign(n, vi(LOG_TWO_N));
		mnIdx.assign(n, vi(LOG_TWO_N));
		for (int i = 0; i < n; i++)
			SpT[i][0] = i, mnIdx[i][0] = i;
		for (int j = 1; (1 << j) <= n; ++j)
			for (int i = 0; i + (1 << j) - 1 < n; ++i)
				if (A[SpT[i][j - 1]] < A[SpT[i + (1 << (j - 1))][j - 1]])
					SpT[i][j] = SpT[i][j - 1], mnIdx[i][j] = mnIdx[i][j - 1];
				else
					SpT[i][j] = SpT[i + (1 << (j - 1))][j - 1],
						mnIdx[i][j] = mnIdx[i + (1 << (j - 1))][j - 1];
	}
	SparseTable() {}
	int query(int i, int j) {
		int k = floor(log2(j - i + 1));
		if (A[SpT[i][k]] <= A[SpT[j - (1 << k) + 1][k]])
			return SpT[i][k];
		else
			return SpT[j - (1 << k) + 1][k];
	}
	int queryIdx(int i, int j) {
		int k = floor(log2(j - i + 1));
		if (A[SpT[i][k]] <= A[SpT[j - (1 << k) + 1][k]])
			return mnIdx[i][k];
		else
			return mnIdx[j - (1 << k) + 1][k];
	}
};

struct LCA {
	int n, idx;
	vi dep, seq, fsOcc;
	SparseTable RMQ;
	void dfs(int node, int depth, int parent) {
		fsOcc[node] = idx;
		seq[idx] = node;
		dep[idx++] = depth;
		for (auto& pr : adj[node])
			if (pr.fs != parent) {
				dfs(pr.fs, depth + 1, node);
				seq[idx] = node;
				dep[idx++] = depth;
			}
	}
	LCA(int _n, int root) {
		n = _n;
		dep.assign(2 * n, 0);
		seq.assign(2 * n, 0);
		fsOcc.assign(n, 0);
		idx = 0;
		dfs(root, 0, -1);
		RMQ = SparseTable(dep);
	}
	int query(int u, int v) {
		if (fsOcc[u] > fsOcc[v])
			swap(u,v);
		return seq[RMQ.query(fsOcc[u], fsOcc[v])];
	}
};

void dfs(int node, int par, int dist) {
	db(node, E, W);
	D[node] = dist;
	for (auto& data : nodeQuery[node])
		ans[data.fs] += data.sc.sc.sc * (D[node] + data.sc.sc.fs * E[data.sc.fs] - W[data.sc.fs]);

	for (auto& pr : adj[node])
		if (pr.fs != par) {
			++E[pr.sc.fs];
			W[pr.sc.fs] += pr.sc.sc;
			dfs(pr.fs, node, dist + pr.sc.sc);
			--E[pr.sc.fs];
			W[pr.sc.fs] -= pr.sc.sc;
		}
}

struct TreeSqrtTrick {
	int n, n_sqrt;
	vvi lvl, Data_c, Data_w;
	V<bool> special;
	V<pair<int, pii>> par;
	vi dist;
	void dfs(int node, int depth, int parent, int d = 0) {
		lvl[depth].pb(node);
		dist[node] = d;
		for (auto& pr : adj[node])
			if (pr.fs != parent)
				par[pr.fs] = mp(node, pr.sc), dfs(pr.fs, depth + 1, node, d + pr.sc.sc);
	}
	TreeSqrtTrick(int _n, int root) {
		n = _n;
		n_sqrt = sqrt(n) + 1;
		lvl.assign(n, vi());
		special.assign(n + 1, 0);
		par.assign(n + 1, mp(-1, mp(-1, -1)));
		dist.assign(n + 1, 0);
		Data_c.assign(n + 1, vi());
		Data_w.assign(n + 1, vi());
		dfs(root, 0, -1);

		for (int lv = n - 1; lv >= 0; --lv)
			for (auto& u : lvl[lv]) {
				int curr = u;

				for (int i = 1; i <= n_sqrt; ++i)
					if (special[curr] || par[curr].fs == -1)
						break;
					else
						curr = par[curr].fs;

				special[curr] = true;
			}

		db(special);

		for (int i = 1; i <= n; ++i)
			if (special[i]) {
//				; // process i and store its output in Data[i]
				Data_w[i].assign(n, 0);
				Data_c[i].assign(n, 0);
				int curr = i;
				while (par[curr].fs != -1) {
					int c = par[curr].sc.fs;
					int d = par[curr].sc.sc;
					++Data_c[i][c];
					Data_w[i][c] += d;
					curr = par[curr].fs;
				}
			}
	}
	int f(int u, int x, int y) {
		int curr = u, ret = dist[u], c_x = 0, w_x = 0;
		while (!special[curr]) {
			int c = par[curr].sc.fs;
			int d = par[curr].sc.sc;
			if (c == x)
				++c_x, w_x += d;
			curr = par[curr].fs;
		}
		c_x += Data_c[curr][x];
		w_x += Data_w[curr][x];
		return ret - w_x + c_x * y;
	}
};

int main() {
	#ifdef LOCAL
	auto stTime = clock();
//	freopen("in.txt", "r", stdin);
	#endif
	ios::sync_with_stdio(false);
	cout.precision(10);
	cin.tie(0);

	cin >> N >> Q;
	adj.assign(N + 1, V<pair<int, pii>>());
	nodeQuery.assign(N + 1, V<pair<int, pair<int, pii>>>());
	D.assign(N + 1, 0);
	E.assign(N, 0);
	W.assign(N, 0);
	int u, v, c, d;
	for (int i = 0; i < N - 1; ++i) {
		cin >> u >> v >> c >> d;
		adj[u].pb(mp(v, mp(c, d)));
		adj[v].pb(mp(u, mp(c, d)));
	}
	LCA lca(N, 1);
	TreeSqrtTrick tst(N, 1);
	int x, y;
	for (int i = 0; i < Q; ++i) {
		cin >> x >> y >> u >> v;
		int w = lca.query(u, v);
		cout << tst.f(u, x, y) + tst.f(v, x, y) - 2 * tst.f(w, x, y) << '\n';
	}

	#ifdef LOCAL
	cout << "\n\n\nExecution time: " <<
		(clock() - stTime) * 1e3 / CLOCKS_PER_SEC << " ms" << endl;
	#endif
    return 0;
}


Measured memory_bytes: 327040