#include <iostream>
#include <vector>
#include <limits.h>
#include <algorithm>
#include <string>
#include <math.h>
#include <limits.h>
#include <queue>
#include <map>
#include <set>
#include <iomanip>
#include <bitset>
#include <cassert>
#include <random>
#include <functional>
#include <stack>
#include <iomanip>
#include <cassert>
//#include <boost/multiprecision/cpp_int.hpp>
#include <complex>
#include <cstdio>
#include <list>
#include <bitset>

//< in.txt > out.txt
using namespace std;
//std::ios::sync_with_stdio(false);
//std::cin.tie(0);
const long long MOD = 998244353;
const long long INF = 1e18;
typedef long long LL;
typedef long double LD;
typedef pair<LL, LL> PLL;
typedef pair<LD, LL> pdl;
typedef pair<LD, LD> pdd;
typedef vector<LL> VLL;
typedef vector<VLL> VVLL;
typedef unsigned long long ULL;
//typedef boost::multiprecision::cpp_int bigint;

template<class T>
struct Gedge {
	LL src,to;
	T cost;
	Gedge(LL s,LL t, T c) :src(s),to(t), cost(c) {}
	Gedge(LL t, T c) :src(-1), to(t), cost(c) {}
};

template<class T>
using WeightedGraph = vector<vector<Gedge<T>>>;
using UnweightedGraph = vector<vector<LL>>;
template<class T>
using Gedges = vector<Gedge<T>>;

//require Monoid
template<class T>
class Segtree {
private:
	vector<T> seg;
	LL RN;
public:
	Segtree(LL N) {
		RN = 1;
		while (RN < N)RN *= 2;
		seg.resize(2 * RN, T());
	}
	Segtree(vector<T>& V) {
		LL N = V.size();
		RN = 1;
		while (RN < N)RN *= 2;
		seg.resize(2 * RN, T());
		for (LL n = 0; n < N; n++) seg[RN + n] = V[n];
		for (LL k = RN - 1; k >= 1; k--) {
			seg[k] = seg[2 * k] * seg[2 * k + 1];
		}
	}
	//set n-th as x(0 index!!!!!)
	void set(LL n, T x) {
		seg[RN + n] = x;
		n = (RN + n) / 2;
		while (n >= 1) {
			seg[n] = seg[2 * n] * seg[2 * n + 1];
			n /= 2;
		}
	}
	//change n-th number p to x*p(0 index!!!!!)
	void addl(LL n, T x) {
		seg[RN + n] = x*seg[RN+n];
		n = (RN + n) / 2;
		while (n >= 1) {
			seg[n] = seg[2 * n] * seg[2 * n + 1];
			n /= 2;
		}
	}
	//change n-th number p to p*x(0 index!!!!!)
	void addr(LL n, T x) {
		seg[RN + n] = seg[RN + n]*x;
		n = (RN + n) / 2;
		while (n >= 1) {
			seg[n] = seg[2 * n] * seg[2 * n + 1];
			n /= 2;
		}
	}
	//get [l,r] (0 index!!!!!)
	T get(LL l, LL r) {
		T ansl, ansr;
		r++;
		l += RN;
		r += RN;
		while (l < r) {
			if (l & 1) {
				ansl = ansl * seg[l];
				l++;
			}
			if (r & 1) {
				r--;
				ansr = seg[r] * ansr;
			}
			l >>= 1;
			r >>= 1;
		}
		return ansl * ansr;
	}
	//get n-th number(0 index!!!!!)
	T get(LL n) {
		return seg[RN + n];
	}
	T operator[](LL n) {
		return seg[RN + n];
	}
};

struct TNode {
	LL parent;
	VLL childs;
	TNode() :parent(-1) {};
};
using Tree = vector<TNode>;

void ETSdfs(Tree& G, LL& id, vector<PLL>& range, LL n) {
	range[n].first = id++;
	for (LL ch : G[n].childs) {
		ETSdfs(G, id, range,ch);
	}
	range[n].second = id-1;
}

//dfs:dfsした順に頂点が格納される(重複無し、size = V)
//range:range[n] = (u,v) <==> dfs上でnの部分木は[u,v]
void EulerTour_subtree(Tree& G, vector<PLL>& range, LL root = 0) {
	range.resize(G.size());
	LL id = 0;
	ETSdfs(G, id, range, root);
}

struct ETPsegnode {
	LL n;
	LL d;
	ETPsegnode() :n(0), d(1e9) {};
	ETPsegnode(LL _n, LL _d) :n(_n), d(_d) {};
};

ETPsegnode operator*(ETPsegnode a, ETPsegnode b) {
	if (a.d < b.d)return a;
	else return b;
}

void ETPdfs(Tree& G, LL& ord, vector<ETPsegnode>& dfs, vector<PLL>& id, LL n) {
	if (ord == 0)dfs[ord] = { n, 0 };
	else {
		dfs[ord] = { n, dfs[ord - 1].d+1 };
	}
	id[n].first = ord++;
	for (LL ch : G[n].childs) {
		ETPdfs(G, ord, dfs, id, ch);
		dfs[ord] = { n, dfs[ord - 1].d-1 };
		ord++;
	}
	id[n].second = ord-1;
}

//dfs:dfsした順に頂点およびその深さが格納される(重複あり、size=2*V-1)
//id:dfsである頂点vが最初に出てくる添え字(つまりvの親->vをした時の添え字)
//辺(p(u),u)をxに更新
//->seg[id[u].first-1]をx、seg[id[u].second]を-xに
//パス(u,v) (lca(u,v) == u)での和を取得
//->seg[id[u].first]+...+seg[id[v].first-1]
void EulerTour_path(Tree& G, vector<ETPsegnode>& dfs, vector<PLL>& id, LL root = 0) {
	dfs.resize(2*G.size()-1);
	id.resize(G.size());
	LL ord = 0;
	ETPdfs(G, ord, dfs, id, root);
}

ETPsegnode LCA(Segtree<ETPsegnode>& seg, vector<PLL>& id,LL u,LL v) {
	if (id[u] > id[v])swap(u, v);
	return seg.get(id[u].first, id[v].first);
}

void SetTree(UnweightedGraph& G, Tree& T, LL root = 0) {
	T.resize(G.size());
	stack<PLL> st;
	st.push(PLL(root, -1));
	while (!st.empty()) {
		LL cur = st.top().first;
		LL p = st.top().second;
		st.pop();
		T[cur].parent = p;
		for (LL ch : G[cur]) {
			if (ch == p)continue;
			T[cur].childs.push_back(ch);
			st.push(PLL(ch, cur));
		}
	}
}

class Monoid {
public:
	LL v;
	Monoid(LL _v) :v(_v) {};
	Monoid() :v(0) {};
};
Monoid operator*(Monoid a, Monoid b) {
	return Monoid(a.v + b.v);
}

int main() {
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);
	LL N, Q;
	cin >> N >> Q;
	Tree T;
	Segtree<Monoid> segn(1), segd(1);
	vector<PLL> id;
	Segtree<ETPsegnode> lcaseg(1);
	vector<vector<Gedge<LL>>> edges(N);   //src:親,to:子,cost:cost
	struct query {
		LL num;
		LL y;
		LL u,v;
		query(LL n, LL _y, LL _u,LL _v) :num(n), y(_y), u(_u),v(_v) {};
	};
	vector<vector<query>> querys(N);
	{
		UnweightedGraph G(N);
		VLL A(N), B(N), C(N);
		vector<Monoid> D(N);
		for (LL n = 0; n < N-1; n++) {
			cin >> A[n] >> B[n] >> C[n] >> D[n].v;
			A[n]--;
			B[n]--;
			G[A[n]].push_back(B[n]);
			G[B[n]].push_back(A[n]);
		}
		SetTree(G, T);
		vector<ETPsegnode> dfsres;
		EulerTour_path(T, dfsres, id);
		lcaseg = Segtree<ETPsegnode>(dfsres);
		segn = Segtree<Monoid>(2*N-1);
		segd = Segtree<Monoid>(2*N-1);
		for (LL n = 0; n < N-1; n++) {
			//A[n]がB[n]の親
			if (B[n] == T[A[n]].parent)swap(A[n], B[n]);
			edges[C[n]].push_back(Gedge<LL>(A[n], B[n], D[n].v));
			segd.addl(id[B[n]].first - 1, D[n]);
			segd.addl(id[B[n]].second, Monoid(-D[n].v));
		}
		for (LL q = 0; q < Q; q++) {
			LL x, y, u, v;
			cin >> x >> y >> u >> v;
			u--; v--;
			querys[x].push_back({ q,y,u,v });
		}
	}
	VLL ans(Q);
	for (LL color = 0; color < N; color++) {
		if (querys[color].size() == 0)continue;
		for (Gedge<LL>& e : edges[color]) {
			LL n = e.to;
			segn.addl(id[n].first - 1, 1);
			segn.addl(id[n].second, -1);
			segd.set(id[n].first - 1, 0);
			segd.set(id[n].second, 0);
		}
		for (query& que : querys[color]) {
			LL u = que.u;
			LL v = que.v;
			LL lca = LCA(lcaseg, id,u,v).n;
			LL p, q;
			if (lca == u) {
				p = segd.get(id[lca].first, id[v].first - 1).v;
				q = segn.get(id[lca].first, id[v].first - 1).v;
			}
			else if (lca == v) {
				p = segd.get(id[lca].first, id[u].first - 1).v;
				q = segn.get(id[lca].first, id[u].first - 1).v;
			}
			else {
				p = segd.get(id[lca].first, id[v].first - 1).v;
				q = segn.get(id[lca].first, id[v].first - 1).v;
				p += segd.get(id[lca].first, id[u].first - 1).v;
				q += segn.get(id[lca].first, id[u].first - 1).v;
			}
			ans[que.num] = p + q * que.y;
		}
		for (Gedge<LL>& e : edges[color]) {
			LL n = e.to;
			segn.addl(id[n].first - 1, -1);
			segn.addl(id[n].second, 1);
			segd.set(id[n].first - 1, e.cost);
			segd.set(id[n].second, -e.cost);
		}
	}
	for (LL q = 0; q < Q; q++) {
		cout << ans[q] << "\n";
	}
	return 0;
}


Measured memory_bytes: 56432