#include "bits/stdc++.h"

using namespace std;
#ifdef _DEBUG
#define _GLIBCXX_DEBUG
#include "dump.hpp"
#else
#define dump(...)
#endif

#define int long long
#define ll long long
#define DBG 1
#define rep(i, a, b) for (int i = (a); i < (b); i++)
#define rrep(i, a, b) for (int i = (b)-1; i >= (a); i--)
#define loop(n) rep(loop, (0), (n))
#define all(c) begin(c), end(c)
const int INF = sizeof(int) == sizeof(long long) ? 0x3f3f3f3f3f3f3f3fLL : 0x3f3f3f3f;
const int MOD = (int)(1e9) + 7;
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
using pii = pair<int, int>;
// template<class T> ostream &operator<<(ostream &os,T &t){dump(t);return os;}
template <typename T, typename S>istream &operator>>(istream &is, pair<T, S> &p) { is >> p.first >> p.second; return is; }
//template <typename T, typename S>ostream &operator<<(ostream &os, pair<T, S> &p) {os << p.first << " " << p.second;return os;}

template <typename T> void printvv(const vector<vector<T>> &v) {
	cerr << endl;
	rep(i, 0, v.size()) rep(j, 0, v[i].size()) {
		if (typeid(v[i][j]).name() == typeid(INF).name() and v[i][j] == INF) {
			cerr << "INF";
		}
		else
			cerr << v[i][j];
		cerr << (j == v[i].size() - 1 ? '\n' : ' ');
	}
	cerr << endl;
}

#ifndef _DEBUG
#define printvv(...)
#endif
void YES(bool f) { cout << (f ? "YES" : "NO") << endl; }
void Yes(bool f) { cout << (f ? "Yes" : "No") << endl; }
template <class T, class U>bool chmin(T& a, U b) { if (a > b) { a = b; return true; }return false; }
template <class T, class U>bool chmax(T& a, U b) { if (a < b) { a = b; return true; }return false; }

using Weight = int;
using Flow = int;
struct Edge {
	int s, d; Weight w; Flow c;
	int color;
	Edge() {};
	Edge(int s, int d, int color, Weight w = 1) : s(s), d(d), color(color), w(w), c(w) {};
};
bool operator<(const Edge &e1, const Edge &e2) { return e1.w < e2.w; }
bool operator>(const Edge &e1, const Edge &e2) { return e2 < e1; }
inline ostream &operator<<(ostream &os, const Edge &e) { return (os << '(' << e.s << ", " << e.d << ", " << e.w << ", " << e.color << ')'); }

using Edges = vector<Edge>;
using Graph = vector<Edges>;
using Array = vector<Weight>;
using Matrix = vector<Array>;

void addArc(Graph &g, int s, int d, int color, Weight w = 1) {
	g[s].emplace_back(s, d, color, w);
}
void addEdge(Graph &g, int a, int b, int color, Weight w = 1) {
	addArc(g, a, b, color, w);
	addArc(g, b, a, color, w);
}


struct LCA { // rooted tree
	using Node = int;
	vector<vector<Node>> parent;
	Graph g;
	int root, V, log2_n;
	vector<Node> depth;
	vector<Weight>dist;
	int get_depth(int x) { return depth[x]; }
	vector<set<int>>q;
	vector<map<int, pii>>mp;
	vector<pii>tmp;
	void build() {
		dfs2(root, -1);
	}
	void dfs2(int root, int par) {
		dump(root, par, tmp);
		for (auto qq : q[root]) {
			mp[root][qq] = tmp[qq];
		}
		for (auto e : g[root]) {
			if (e.d == par)continue;
			tmp[e.color].first += e.w;
			tmp[e.color].second++;
			dfs2(e.d, root);
			tmp[e.color].first -= e.w;
			tmp[e.color].second--;
		}
	}

	void dfs(int v, int p, int _depth, Weight w) {
		parent[0][v] = p;
		depth[v] = _depth;
		dist[v] = w;
		for (const auto &e : g[v]) {
			if (e.d == p)continue;
			dfs(e.d, v, _depth + 1, w + e.w);
		}
	}
	LCA(const Graph &G, int root)
		: root(root), V(G.size()), g(G), depth(V), log2_n(1 + (int)log2(V)), dist(V), q(V), tmp(V), mp(V) {
		parent.resize(log2_n, vector<Node>(V));
		dfs(root, -1, 0, 0);
		for (int k = 0; k + 1 < log2_n; k++) {
			for (int v = 0; v < V; v++) {
				auto p = parent[k][v];
				if (p < 0) {
					parent[k + 1][v] = -1;
				}
				else {
					parent[k + 1][v] = parent[k][p];
				}
			}
		}
	}
	Node query(int u, int v) {
		if (depth[u] > depth[v])
			swap(u, v);
		for (int k = 0; k < log2_n; k++) {
			if ((depth[v] - depth[u]) >> k & 1) {
				v = parent[k][v];
			}
		}
		if (u == v)
			return u;
		for (int k = log2_n - 1; k >= 0; k--) {
			if (parent[k][u] != parent[k][v]) {
				u = parent[k][u];
				v = parent[k][v];
			}
		}
		return parent[0][u];
	}
	Weight distance(int u, int v) {
		Node lca = query(u, v);
		return dist[u] + dist[v] - 2 * dist[lca];
	}
};

signed main(signed argc, char *argv[]) {
	cin.tie(0);
	ios::sync_with_stdio(false);
	cout << fixed << setprecision(12);

	int N, Q; cin >> N >> Q;
	Graph g(N);
	loop(N - 1) {
		int a, b, c, d; cin >> a >> b >> c >> d;
		a--, b--;
		addEdge(g, a, b, c, d);
	}
	dump(g);
	LCA lca(g, 0);
	dump(lca.dist);
	vector<int>x(Q), y(Q), u(Q), v(Q); rep(i, 0, Q) { cin >> x[i] >> y[i] >> u[i] >> v[i]; u[i]--, v[i]--; }

	rep(i, 0, Q) {
		int l = lca.query(u[i], v[i]);
		lca.q[u[i]].emplace(x[i]);
		lca.q[v[i]].emplace(x[i]);
		lca.q[l].emplace(x[i]);
	}
	lca.build();
	dump(lca.mp);
	dump("build");
	rep(i, 0, Q) {
		int l = lca.query(u[i], v[i]);
		int ans = lca.distance(u[i], v[i]);
		dump(l, ans);
		auto q = lca.mp[u[i]][x[i]];
		ans += y[i] * q.second - q.first;
		dump(q, ans);
		q = lca.mp[v[i]][x[i]];
		ans += y[i] * q.second - q.first;
		dump(q, ans);
		q = lca.mp[l][x[i]];
		ans -= (y[i] * q.second - q.first) * 2;
		dump(q, ans);
		cout << ans << endl;
	}

	return 0;
}


Measured memory_bytes: 79632