#include <bits/stdc++.h>

using namespace std;

const int LIMIT = 1e5, INF = 1e9;
int t = 0;
vector<tuple<int, int, int>> adj[LIMIT];
int tin[LIMIT], tout[LIMIT], dist[LIMIT], walk[LIMIT << 1], depthWalk[LIMIT << 1];
map<int, vector<pair<int,int>>> colorEdges;
unordered_map<int, int*> cumlativeWeights, cumlativeCount;

void dfs(int u, int p = -1, int depth = 0) {
	int v, c, d;
	walk[t] = u;
	depthWalk[t] = depth;
	tin[u] = t++;
	for(auto e : adj[u]) {
		tie(v, c, d) = e;
		if(v == p) continue;
		dist[v] = dist[u] + d;
		colorEdges[c].push_back({t - 1, d});
		dfs(v, u, depth + 1);
		colorEdges[c].push_back({t, -d});
		depthWalk[t] = depth;
		walk[t++] = u;
	}
	tout[u] = t - 1;
}

void generateCumlative() {
	for(auto e : colorEdges) {
		cumlativeWeights[e.first] = new int[e.second.size()];
		cumlativeWeights[e.first][0] = e.second[0].second;
		cumlativeCount[e.first] = new int[e.second.size()];
		cumlativeCount[e.first][0] = e.second[0].second > 0 ? 1 : -1;
		for(int i = 1; i < e.second.size(); i++) {
			cumlativeWeights[e.first][i] = cumlativeWeights[e.first][i - 1] + e.second[i].second;
			cumlativeCount[e.first][i] = cumlativeCount[e.first][i - 1] + (e.second[i].second > 0 ? 1 : -1);
		}
	}
}

tuple<int, int, bool> getColorRange(int c, int t1, int t2) {
	auto& v = colorEdges[c];
	auto l = lower_bound(v.begin(), v.end(), make_pair(t1, -LIMIT)) - v.begin();
	auto r = lower_bound(v.begin(), v.end(), make_pair(t2, -LIMIT)) - v.begin();
	if(l == r) return make_tuple(-1, -1, false);
	return make_tuple(l, r - 1, true);
}

template<typename T>
struct SegmentTree {     // One-based except Input Array
	int N;
	T* input;
	vector<T> lazy;
	vector<T> stree;

	inline T f(T a, T b) {
		if(a == INF) return b;
		if(b == INF) return a;
		return input[b] < input[a] ? b : a;
	}

	void build(int v, int l, int r) {
		if(l == r) {
			stree[v] = l - 1;
			return;
		}
		int mid = (l + r) >> 1;
		build(v << 1, l, mid);
		build(v << 1 | 1, mid + 1, r);
		stree[v] = f(stree[v << 1], stree[v << 1 | 1]);
	}

	SegmentTree(T arr[], int n) {
		input = arr;
		N = n;
		int sz = 1;
		while(sz < N)
			sz <<= 1;
		stree.assign(sz << 1, 0);
		lazy.assign(sz << 1, 0);
		build(1, 1, N);
	}

	void updateRange(int l, int r, T val) {
		updateRange(1, 1, N, l, r, val);
	}

	T query(int v, int l, int r, int queryStart, int queryEnd) {
		if(r < queryStart || l > queryEnd)
			return INF; //dummy variable
		if(l >= queryStart && r <= queryEnd)
			return stree[v];
		int mid = (l + r) >> 1;
		T q1 = query(v << 1, l, mid, queryStart, queryEnd);
		T q2 = query(v << 1 | 1, mid + 1, r, queryStart, queryEnd);
		return f(q1, q2);
	}

	T query(int l, int r) {
		return query(1, 1, N, l, r);
	}
};


int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(nullptr);
	int n, q, u, v, c, d;
	cin >> n >> q;
	for(int i = 0; i < n - 1; i++) {
		cin >> u >> v >> c >> d;
		--u; --v; --c;
		adj[u].push_back(make_tuple(v, c, d));
		adj[v].push_back(make_tuple(u, c, d));
	}
	for(int i = 0; i < LIMIT << 1; i++)
		depthWalk[i] = INF;
	dist[0] = 0;
	dfs(0);
	generateCumlative();
	SegmentTree<int> table(depthWalk, LIMIT << 1);
	while(q--) {
		cin >> c >> d >> u >> v;
		--c; --u; --v;
		int l = tin[u], r = tin[v], cl, cr;
		if(l > r) swap(l, r);
		int lca = walk[table.query(l + 1, r + 1)];
		bool validColorRange;
		int distance = dist[u] + dist[v] - 2 * dist[lca];
		if(u != lca) {
			tie(cl, cr, validColorRange) = getColorRange(c, tin[lca], tin[u]);
			if (validColorRange)
				distance += -(cumlativeWeights[c][cr] - (cl > 0 ? cumlativeWeights[c][cl - 1] : 0)) + (cumlativeCount[c][cr] - (cl > 0 ? cumlativeCount[c][cl - 1] : 0)) * d;
		}
		if(v != lca) {
			tie(cl, cr, validColorRange) = getColorRange(c, tin[lca], tin[v]);
			if (validColorRange)
				distance += -(cumlativeWeights[c][cr] - (cl > 0 ? cumlativeWeights[c][cl - 1] : 0)) + (cumlativeCount[c][cr] - (cl > 0 ? cumlativeCount[c][cl - 1] : 0)) * d;
		}
		cout << distance << '\n';
	}
	return 0;
}



Measured memory_bytes: 35936