#include <bits/stdc++.h>
using namespace std;
#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define REP(i,n) FOR(i,0,n)
#define ALL(v) begin(v),end(v)
#define fi first
#define se second
template<typename A, typename B> inline bool chmax(A &a, B b) { if (a<b) { a=b; return 1; } return 0; }
template<typename A, typename B> inline bool chmin(A &a, B b) { if (a>b) { a=b; return 1; } return 0; }
using ll = long long;
using pii = pair<int, int>;
constexpr ll INF = 1ll<<30;
constexpr ll longINF = 1ll<<60;
constexpr ll MOD = 1000000007;
constexpr bool debug = 0;
//---------------------------------//

template<typename T>
struct SegmentTree {
	using value_type = T;
	using const_reference = const value_type &;
	using F = std::function<value_type(const_reference, const_reference)>;
	using size_type = std::size_t;
	
	SegmentTree(size_type n_, const F & f, const_reference id_elem) : f(f), id_elem(id_elem) {
		n = 1;
		while (n < n_) n <<= 1;
		node.resize(2 * n, id_elem);
	}
	
	size_type size() const noexcept {
		return n;
	}
	
	void set(size_type i, const_reference x) {
		assert(i < size());
		node[i += n] = x;
		while (i > 1) {
			i >>= 1;
			node[i] = f(node[i << 1], node[i << 1 | 1]);
		}
	}
	
	void add(size_type i, const_reference x) {
		assert(i < size());
		i += n;
		node[i] = f(node[i], x);
		while (i > 1) {
			i >>= 1;
			node[i] = f(node[i << 1], node[i << 1 | 1]);
		}
	}
	
	value_type fold(size_type l, size_type r) const {
		assert(l <= size() && r <= size());
		std::vector<size_type> front, back;
		value_type lv = id_elem, rv = id_elem;
		for (l += n, r += n; l < r; l >>= 1, r >>= 1) {
			if (l & 1) lv = f(lv, node[l++]);
			if (r & 1) rv = f(node[r - 1], rv);
		}
		return f(lv, rv);
	}
	
	size_type lower_bound(const_reference x) const {
		if (node[1] < x) return n;
		size_type idx;
		value_type s = id_elem;
		for (idx = 1; idx < n;) {
			value_type nex = f(s, node[idx << 1]);
			if (nex < x) {
				idx = idx << 1 | 1;
				s = nex;
			}
			else idx = idx << 1;
		}
		return idx - n;
	}
	
	size_type upper_bound(const_reference x) const {
		if (node[1] <= x) return n;
		size_type idx;
		value_type s = id_elem;
		for (idx = 1; idx < n;) {
			value_type nex = f(s, node[idx << 1]);
			if (nex <= x) {
				idx = idx << 1 | 1;
				s = nex;
			}
			else idx = idx << 1;
		}
		return idx - n;
	}
	
private:
	size_type n;
	F f;
	value_type id_elem;
	std::vector<value_type> node;
};

template<typename U, template<typename> typename T>
struct HeavyLightDecomposition {
public:
	using value_type = U;
	using container_type = T<U>;
	using const_reference = const value_type &;
	using F = std::function<value_type(const_reference, const_reference)>;
	using size_type = std::size_t;
	
	HeavyLightDecomposition(std::vector<std::vector<size_type>> &g, size_type root_num, const F &f, const_reference id_elem, bool value_on_vertex) : f(f), id_elem(id_elem), value_on_vertex(value_on_vertex) {
		build(g, root_num);
	}
	
	size_type size() const noexcept {
		return size_;
	}
	
	void set(size_type i, const_reference x) {
		assert(value_on_vertex);
		assert(i < size());
		set_(i, x);
	}
	
	void set(size_type u, size_type v, const_reference x) {
		assert(!value_on_vertex);
		assert(u < size() && v < size());
		assert(par_num[u] == v || par_num[v] == u);
		size_type i = par_num[u] == v ? u : v;
		set_(i, x);
	}
	
	value_type fold(size_type u, size_type v) const {
		assert(u < size() && v < size());
		size_type lca_node = node_idx[lca_node_num(u, v).first];
		value_type lv = id_elem, rv = id_elem;
		
		while (node_idx[u] != lca_node) {
			lv = f(lv, value[node_idx[u]].fold(path_idx[u], ver_num[node_idx[u]].size()));
			u = par_num[ver_num[node_idx[u]].back()];
		}
		while (node_idx[v] != lca_node) {
			rv = f(rvalue[node_idx[v]].fold(0, get_r_path_idx(node_idx[v], path_idx[v]) + 1), rv);
			v = par_num[ver_num[node_idx[v]].back()];
		}
		
		if (path_idx[u] <= path_idx[v]) lv = f(lv, value[node_idx[u]].fold(path_idx[u], path_idx[v] + value_on_vertex));
		else rv = f(rvalue[node_idx[u]].fold(get_r_path_idx(node_idx[u], path_idx[u]) + !value_on_vertex, get_r_path_idx(node_idx[v], path_idx[v]) + 1), rv);
		
		return f(lv, rv);
	}
	
	size_type lca(size_type x, size_type y) const {
		assert(x < size() && y < size());
		std::pair<size_type, size_type> res = lca_node_num(x, y);
		return ver_num[node_idx[res.first]][std::max(path_idx[res.first], path_idx[res.second])];
	}
	
private:
	F f; // 二項演算 f
	const value_type id_elem; // 単位元
	bool value_on_vertex; // 値が {true : 頂点, false : 辺} に存在する
	size_type size_; // 分解前の頂点数
	std::vector<size_type> node_idx; // node_idx[i] := 頂点 i が属する分解後の列の index
	std::vector<size_type> path_idx; // path_idx[i] := 頂点 i が属する分解後の列での頂点 i の index
	std::vector<std::vector<size_type>> ver_num; // [i][j] := 分解後の列 i の j 番目の要素の分解前の頂点番号
	
	std::vector<size_type> par_num; // par_num[i] := 頂点 i の親の頂点番号
	std::vector<std::vector<size_type>> childs; // childs[i] := 頂点 i の子の頂点番号
	std::vector<container_type> value, rvalue; // 頂点や辺の値, rvalue は逆向きの演算
	
	void build(const std::vector<std::vector<size_type>> &g, size_type root_num) {
		size_ = g.size();
		node_idx.resize(size());
		path_idx.resize(size());
		par_num.resize(size());
		childs.resize(size());
		
		std::vector<bool> done(size(), 0);
		std::vector<size_type> sub_size(size(), 0);
		
		std::stack<std::pair<size_type, size_type>> stk;
		stk.emplace(root_num, 0);
		par_num[root_num] = root_num;
		done[root_num] = true;
		
		while (!stk.empty()) {
			int u = stk.top().first;
			int idx = stk.top().second;
			stk.pop();
			
			if (idx < g[u].size()) {
				stk.emplace(u, idx + 1);
				
				int v = g[u][idx];
				if (!done[v]) {
					done[v] = true;
					par_num[v] = u;
					childs[u].push_back(v);
					stk.emplace(v, 0);
				}
			}
			else {
				size_type mx_idx, mx_size = 0, size_cnt = 1;
				for (size_type child : childs[u]) {
					size_cnt += sub_size[child];
					if (mx_size < sub_size[child]) {
						mx_size = sub_size[child];
						mx_idx = child;
					}
				}
				
				if (size_cnt == 1) ver_num.emplace_back();
				size_type cur_node_idx = size_cnt == 1 ? ver_num.size() - 1 : node_idx[mx_idx];
				sub_size[u] = size_cnt;
				node_idx[u] = cur_node_idx;
				path_idx[u] = ver_num[node_idx[u]].size();
				ver_num[node_idx[u]].emplace_back(u);
			}
		}
		
		for (size_type i = 0; i < ver_num.size(); ++i) {
			value.emplace_back(ver_num[i].size(), f, id_elem);
			rvalue.emplace_back(ver_num[i].size(), f, id_elem);
		}
	}
	
	std::pair<size_type, size_type> lca_node_num(size_type x, size_type y) const {
		assert(x < size() && y < size());
		if (node_idx[x] == node_idx[y]) return {x, y};
		std::stack<size_type> stk[2];
		for (size_type i = 0; i < 2; ++i) {
			stk[i].emplace(-1);
			stk[i].emplace(i == 0 ? x : y);
			while (true) {
				size_type top_num = ver_num[node_idx[stk[i].top()]].back();
				size_type par = par_num[top_num];
				if (top_num == par) break;
				stk[i].emplace(par);
			}
		}
		
		size_type lca_pred[2];
		while (node_idx[stk[0].top()] == node_idx[stk[1].top()]) {
			for (size_type i = 0; i < 2; ++i) {
				lca_pred[i] = stk[i].top();
				stk[i].pop();
			}
		}
		return {lca_pred[0], lca_pred[1]};
	}
	
	size_type get_r_path_idx(size_type nidx, size_type pidx) const {
		assert(nidx < ver_num.size());
		assert(pidx < ver_num[nidx].size());
		return ver_num[nidx].size() - pidx - 1;
	}
	
	void set_(size_type i, const_reference x) {
		assert(i < size());
		value[node_idx[i]].set(path_idx[i], x);
		rvalue[node_idx[i]].set(get_r_path_idx(node_idx[i], path_idx[i]), x);
	}
};

int main() {
	int N, Q;
	cin >> N >> Q;
	vector<vector<std::size_t>> g(N);
	vector<int> A(N - 1), B(N - 1), C(N - 1), D(N - 1);
	vector<vector<int>> colv(N - 1);
	
	REP(i, N - 1) {
		scanf("%d %d %d %d", &A[i], &B[i], &C[i], &D[i]);
		--A[i]; --B[i]; --C[i];
		g[A[i]].emplace_back(B[i]);
		g[B[i]].emplace_back(A[i]);
		colv[C[i]].emplace_back(i);
	}
	
	vector<int> X(Q), Y(Q), U(Q), V(Q);
	REP(i, Q) {
		scanf("%d %d %d %d", &X[i], &Y[i], &U[i], &V[i]);
		--X[i]; --U[i]; --V[i];
	}
	
	vector<int> ord(Q), ans(Q);
	iota(ALL(ord), 0);
	sort(ALL(ord), [&](int x, int y) {
		return X[x] < X[y];
	});
	
	HeavyLightDecomposition<int, SegmentTree> hld1(g, 0, [](int a, int b) { return a + b; }, 0, false);
	REP(i, N - 1) hld1.set(A[i], B[i], D[i]);
	HeavyLightDecomposition<pii, SegmentTree> hld2(g, 0, [](const pii &x, const pii &y) -> pii {
		return {x.fi + y.fi, x.se + y.se};
	}, pii(0, 0), false);
	
	REP(t, Q) {
		int i = ord[t];
		if (t == 0 || X[ord[t]] != X[ord[t - 1]])
			for (int cur : colv[X[i]]) hld2.set(A[cur], B[cur], {D[cur], 1});
		
		ans[i] = hld1.fold(U[i], V[i]);
		pii fr = hld2.fold(U[i], V[i]);
		ans[i] -= fr.fi;
		ans[i] += fr.se * Y[i];
		
		if (t + 1 < Q && X[ord[t]] != X[ord[t + 1]])
			for (int cur : colv[X[i]]) hld2.set(A[cur], B[cur], {0, 0});
	}
	
	REP(i, Q) printf("%d\n", ans[i]);
	
	return 0;
}


Measured memory_bytes: 88516