#include <cstdio>
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std;

template <typename T> inline void read(T &n) {
    n = 0; char ch; bool neg = false;
    for (ch = getchar(); ch < '0' || ch > '9'; ch = getchar()) if (ch == '-') neg = !neg; n = ch - 48;
    for (ch = getchar(); ch >= '0' && ch <= '9'; ch = getchar()) n = (n << 1) + (n << 3) + ch - 48; if (neg) n = -n;
}
template <typename T> inline void writee(T n) { if (n > 9) writee(n / 10); putchar(n % 10 + 48); }
template <typename T> inline void write(T n) { if (n < 0) { putchar('-'); n = -n; } writee(n); }
template <typename T> inline void writeln(T x) { write(x); putchar('\n'); }

#define st first
#define nd second

const int N = (int) 1e5 + 5;
const int LOGN = (int) log2(N) + 3;
const int INF = (int) 1e9 + 9;

struct TEdge {
	int v, c, w;
	TEdge() {}
	TEdge(int v, int c, int w) : v(v), c(c), w(w) {}
};

struct TNode {
	int in, ou, c, w;
	TNode() {}
	TNode(int in, int ou, int c, int w) : in(in), ou(ou), c(c), w(w) {}
	bool operator < (const TNode &op) const {
		return in == op.in ? ou < op.ou : in < op.in;
	}
} node[N];

struct TQuery {
	int c, w, u, v;
	TQuery() {}
	TQuery(int c, int w, int u, int v) : c(c), w(w), u(u), v(v) {}
} query[N];

int n, q;
vector <TEdge> g[N];

int vtime;
int in[N], ou[N];
TEdge edgeNode[N];

int logn;
int depth[N], dad[N][LOGN];
long long dist[N];

int pos;
long long cntQuery[N], sumQuery[N];

vector <int> color;
bool markColor[N];
vector <int> colOut[N];

struct TData {
	int u, c, idx, minus;
	TData() {}
	TData(int u, int c, int idx, int minus) : u(u), c(c), idx(idx), minus(minus) {}
	bool operator < (const TData &op) const {
		return in[u] < in[op.u];
	}
};

vector <TData> ver;

void dfsEulerTour(int u, int p) {
	in[u] = ++vtime; 
	for (int i = 0; i < g[u].size(); i++) {
		int v = g[u][i].v, w = g[u][i].w;
		if (v == dad[u][0]) continue;
		edgeNode[v] = g[u][i];
		depth[v] = depth[u] + 1;
		dist[v] = dist[u] + w;
		dfsEulerTour(v, dad[v][0] = u);
	}
	ou[u] = ++vtime;
}

void buildLca() {
	for (int k = 1; k <= logn; k++)
		for (int i = 1; i <= n; i++) dad[i][k] = dad[dad[i][k - 1]][k - 1];
}

int findLca(int u, int v) {
	for (int k = logn; k >= 0; k--)
		if (depth[dad[u][k]] >= depth[v]) u = dad[u][k];
	for (int k = logn; k >= 0; k--)
		if (depth[dad[v][k]] >= depth[u]) v = dad[v][k];
	if (u == v) return u;
	for (int k = logn; k >= 0; k--)
		if (dad[u][k] != dad[v][k]) {
			u = dad[u][k];
			v = dad[v][k];
		}
	return dad[u][0];
}

void compress() {
	vector <int> zip; zip.push_back(0);
	for (int i = 1; i <= n; i++) zip.push_back(ou[i]);
	sort(zip.begin(), zip.end());
	for (int i = 1; i <= n; i++) ou[i] = lower_bound(zip.begin(), zip.end(), ou[i]) - zip.begin(); 
}

void init() {
	logn = log2(n) + 1;
	depth[1] = 1;
	dfsEulerTour(1, 0);
	buildLca();
	compress();
	for (int i = 1; i <= n; i++) node[i] = TNode(in[i], ou[i], edgeNode[i].c, edgeNode[i].w);
	pos = 1;
	sort(node + 1, node + 1 + n);
}

vector <pair <int, long long> > fw[N];

void upd(int c, int i, int w) {
	for (; i < fw[c].size(); i += i & -i) {
		fw[c][i].st++;
		fw[c][i].nd += w;
	}
}

pair <int, long long> get(int c, int i) {
	pair <int, long long> res = make_pair(0, 0LL);
	for (; i > 0; i -= i & -i) {
		res.st += fw[c][i].st;
		res.nd += fw[c][i].nd;
	}
	return res;
}

int main() {
	read(n); read(q);
	for (int i = 1; i < n; i++) {
		int u, v, c, w; read(u); read(v); read(c); read(w);
		g[u].push_back(TEdge(v, c, w));
		g[v].push_back(TEdge(u, c, w));
	}
	init();
	for (int i = 1; i <= q; i++) {
		int c, w, u, v; read(c); read(w); read(u); read(v); 
		int p = findLca(u, v);
		query[i] = TQuery(c, w, u, v);
		ver.push_back(TData(u, c, i, 1));
		ver.push_back(TData(v, c, i, 1));
		ver.push_back(TData(p, c, i, -2));
		colOut[c].push_back(ou[u]);
		colOut[c].push_back(ou[v]);
		colOut[c].push_back(ou[p]);
		if (markColor[c] == false) {
			color.push_back(c);
			markColor[c] = true;
		}
	}
	for (int i = 1; i <= n; i++) {
		int c = edgeNode[i].c;
		colOut[c].push_back(ou[i]);
		if (markColor[c] == false) {
			color.push_back(c);
			markColor[c] = true;
		}
	}
	for (int iCol = 0; iCol < color.size(); iCol++) {
		int c = color[iCol];
		sort(colOut[c].begin(), colOut[c].end());
		colOut[c].resize(distance(colOut[c].begin(), unique(colOut[c].begin(), colOut[c].end())));
		fw[c].resize(colOut[c].size() + 2);
	}
	sort(ver.begin(), ver.end());
	for (int i = 0; i < ver.size(); i++) {
		int u = ver[i].u, c = ver[i].c, idx = ver[i].idx, minus = ver[i].minus;
		while (pos <= n && node[pos].in <= in[u]) {
			int position = lower_bound(colOut[node[pos].c].begin(), colOut[node[pos].c].end(), node[pos].ou) - colOut[node[pos].c].begin() + 1;
			if (position < colOut[node[pos].c].size() + 1) upd(node[pos].c, position, node[pos].w);
 			pos++;
		} 
		if (colOut[c].size() == 0) continue;
		pair <int, long long> resRight = get(c, fw[c].size() - 1);
		int position = upper_bound(colOut[c].begin(), colOut[c].end(), ou[u]) - colOut[c].begin();
		pair <int, long long> resLeft = get(c, position);
		long long temp1 = 0, temp2 = 0;
		cntQuery[idx] += 1LL * minus * (resRight.st - resLeft.st);
		sumQuery[idx] += 1LL * minus * (resRight.nd - resLeft.nd);
		if (edgeNode[u].c == c) {
			cntQuery[idx] += 1LL * minus;
			sumQuery[idx] += 1LL * minus * edgeNode[u].w;
		
		}
	}
	for (int i = 1; i <= q; i++) {
		int u = query[i].u, v = query[i].v, p = findLca(u, v), w = query[i].w;
		long long ans = dist[u] + dist[v] - 2LL * dist[p];
		ans -= sumQuery[i];
		ans += cntQuery[i] * w;
		writeln(ans);
	}
	return 0;
}


Measured memory_bytes: 48740