#include <bits/stdc++.h>
using namespace std;

//It is increasingly evident that I forgot how tuples work.
typedef long long int lli;
typedef pair<lli, lli> ii;
#define mkpr make_pair

const int N = 1e5 + 5;

vector<vector<pair<pair<int, ii>, lli>>> adjList(N);

int n, q;
lli output[N];
vector<pair<ii, int>> queries[N];
vector<vector<ii>> colors(N);

////Lowest Common Ancestor////
//DFS Traversal//
ii vLabels[2*N];

//Tells which index v first/last appears in
int vStart[N];

//Distance from the root
lli rootDist[N];

void dfsLabeler(int u, int par, int currDepth) {
	static int index = 0;
	vStart[u] = index;
	vLabels[index++] = mkpr(currDepth, u);
	for(auto vNest: adjList[u]) {
		int v = vNest.first.first;
		if(par != v) {
			rootDist[v] = rootDist[u] + vNest.first.second.second;
			dfsLabeler(v, u, currDepth+1);
			vLabels[index++] = mkpr(currDepth, u);
		}
	}
}

//Rooted at 0
void init_labeling() {
	rootDist[0] = 0;
	dfsLabeler(0, -1, 0);
}
//End of DFS Traversal//

//Sparse Table//
ii sprs[2*N][20];

void init_sparse_table() {
	for(int i=0; i<2*N; i++) {
		sprs[i][0] = vLabels[i];
	}
	for(int j=1; j<20; j++) {
		for(int i=0; i+(1<<(j-1))<2*N; i++) {
			sprs[i][j] = min(sprs[i][j-1], sprs[i+(1<<(j-1))][j-1]);
		}
	}
}

ii getMinInTable(int a, int b) {
	if(a > b) {
		int temp = a; a = b; b = temp;
	}
	if(a==b) return sprs[a][0];
	int gap = b-a+1;
	int powTwo = -1;
	while(gap) {
		powTwo++;
		gap >>= 1;
	}
	return min(sprs[a][powTwo], sprs[b+1-(1<<powTwo)][powTwo]);
}
//End of Sparse Table//

int lca(int x, int y) {
	return getMinInTable(vStart[x], vStart[y]).second;
}

////End of Lowest Common Ancestor////

vector<lli> colorCounter(N, 0);
vector<lli> coloredDistanceCounter(N, 0);

void dfsColor(int u, int par) {
	for(auto q: queries[u]) {
		int colorRequest = q.first.first;
		int colorNewDist = q.first.second;
		int destin = q.second;
		if(destin < N) {
			output[destin] -= coloredDistanceCounter[colorRequest];
			output[destin] += colorCounter[colorRequest]*colorNewDist;
		} else {
			destin -= N;
			output[destin] += 2*coloredDistanceCounter[colorRequest];
			output[destin] -= 2*colorCounter[colorRequest]*colorNewDist;
		}
	}

	for(auto vNest: adjList[u]) {
		int v = vNest.first.first;
		if(v == par) continue;
		colorCounter[vNest.first.second.first]++;
		coloredDistanceCounter[vNest.first.second.first] += vNest.first.second.second;

		dfsColor(v, u);

		colorCounter[vNest.first.second.first]--;
		coloredDistanceCounter[vNest.first.second.first] -= vNest.first.second.second;
	}
}

void init_all() {
	init_labeling();
	init_sparse_table();
}

int main() {
	ios_base::sync_with_stdio(false);
	cin >> n >> q;

	int a, b, c, d;
	for(int i = 0; i < n-1; i++) {
		cin >> a >> b >> c >> d;
		a--; b--; c--;
		adjList[a].push_back(mkpr(mkpr(b, mkpr(c, d)), i));
		adjList[b].push_back(mkpr(mkpr(a, mkpr(c, d)), i));

		colors[c].push_back(mkpr(i, d));
	}

	init_all();

	for(int i = 0; i < q; i++) {
		int x, y, u, v;
		cin >> x >> y >> u >> v;
		x--;
		u--; v--;

		//Last index is now "where to give the answer to"
		
		int herkunft = lca(u, v);
		output[i] = rootDist[u] - 2*rootDist[herkunft] + rootDist[v];
		queries[u].push_back(mkpr(mkpr(x, y), i));
		queries[v].push_back(mkpr(mkpr(x, y), i));
		queries[herkunft].push_back(mkpr(mkpr(x, y), N+i));
	}

	dfsColor(0, -1);

	for(int i = 0; i < q; i++) {
		cout << output[i] << endl;
	}
	
	return 0;
}

Measured memory_bytes: 103024