#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;
		}
}

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);
	ans.assign(Q, 0);
	int x, y;
	for (int i = 0; i < Q; ++i) {
		cin >> x >> y >> u >> v;
		nodeQuery[u].pb(mp(i, mp(x, mp(y, 1))));
		nodeQuery[v].pb(mp(i, mp(x, mp(y, 1))));
		nodeQuery[lca.query(u, v)].pb(mp(i, mp(x, mp(y, -2))));
	}
	dfs(1, -1, 0);
	db(D);
	for (auto& lilAns : ans)
		cout << lilAns << '\n';

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


Measured memory_bytes: 76788