#include <bits/stdc++.h>

#define ln                '\n'
#define all(dat)           dat.begin(), dat.end()
#define loop(i, to)        for (int i = 0; i < to; ++i)
#define cont(i, to)        for (int i = 1; i <= to; ++i)
#define circ(i, fm, to)    for (int i = fm; i <= to; ++i)
#define foreach(i, dat)    for (__typeof(dat.begin()) i = dat.begin(); i != dat.end(); ++i)

typedef long long          num;

using namespace std;

const int nsz = 1e5;
int n, m, ans[nsz + 5];
int rt = 1, w[nsz + 5], c[nsz + 5], siz[nsz + 5], pr[nsz + 5], dep[nsz + 5], hs[nsz + 5], top[nsz + 5], id[nsz + 5];
vector<int> col[nsz + 5];

struct bianry_index_tree {
	int sum[nsz + 5];
	
	void inline upd(int u, int w) {
		for (; u <= n; sum[u] += w, u += u & -u);
	}
	
	int inline qry(int u) {
		int res = 0;
		for (; u > 0; res += sum[u], u -= u & -u);
		return res;
	}
	
	int inline qry(int l, int r) {
		return qry(r) - qry(l - 1);
	}
};
bianry_index_tree tr, sum, cnt;

struct graph {
	int sz, hd[nsz + 5];
	
	struct edge {
		int nxt, to, w, c;
		
		edge(int nxt = 0, int to = 0, int w = 0, int c = 0) {
			this->nxt = nxt, this->to = to, this->w = w, this->c = c;
		}
	};
	edge e[2 * nsz + 5];
	
	inline edge& operator [] (int id) { return e[id]; }
	
	void inline link(int u, int v, int w = 0, int c = 0) {
		e[++sz] = edge(hd[u], v, w, c), hd[u] = sz;
		e[++sz] = edge(hd[v], u, w, c), hd[v] = sz;
	}
};
graph g;

struct query {
	int id, u, v, c, w;
	
	query(int id = 0, int u = 0, int v = 0, int w = 0, int c = 0) {
		this->id = id, this->u = u, this->v = v, this->w = w, this->c = c;
	}
};
vector<query> qy[nsz + 5];

void dfs1(int u = rt) {
	siz[u] = 1;
	for (int i = g.hd[u]; i; i = g[i].nxt) {
		int v = g[i].to;
		if (v == pr[u])  continue;
		w[v] = g[i].w, c[v] = g[i].c;
		col[c[v]].push_back(v);
		pr[v] = u, dep[v] = dep[u] + 1;
		dfs1(v);
		siz[u] += siz[v];
		siz[hs[u]] < siz[v] && (hs[u] = v);
	}
}

void dfs2(int u = rt, int tp = rt) {
	static int t = 0;
	id[u] = ++t;
	top[u] = tp;
	if (!hs[u])  return;
	dfs2(hs[u], tp);
	for (int i = g.hd[u]; i; i = g[i].nxt) {
		int v = g[i].to;
		if (v == pr[u] || v == hs[u])  continue;
		dfs2(v, v);
	}
}

int inline qry(int u, int v, bianry_index_tree &tr = ::tr) {
	int res = 0;
	for (; top[u] != top[v]; v = pr[top[v]]) {
		if (dep[top[u]] > dep[top[v]])  swap(u, v);
		res += tr.qry(id[top[v]], id[v]);
	}
	if (dep[u] > dep[v])  swap(u, v);
	res += tr.qry(id[u] + 1, id[v]);
	return res;
}

void inline solve(int c) {
	loop (i, col[c].size()) {
		int u = col[c][i];
		sum.upd(id[u], +w[u]);
		cnt.upd(id[u], +1);
	}
	loop (i, qy[c].size()) {
		query &q = qy[c][i];
		int id = q.id, u = q.u, v = q.v, w = q.w, res = qry(u, v);
		res += qry(u, v, cnt) * w - qry(u, v, sum);
		ans[id] = res;
	}
	loop (i, col[c].size()) {
		int u = col[c][i];
		sum.upd(id[u], -w[u]);
		cnt.upd(id[u], -1);
	}
}

int main() {
	scanf("%d%d", &n, &m);
	cont (i, n - 1) {
		int u, v, w, c;
		scanf("%d%d%d%d", &u, &v, &c, &w);
		g.link(u, v, w, c);
	}
	dfs1();
	dfs2();
	cont (u, n) {
		tr.upd(id[u], w[u]);
	}
	cont (i, m) {
		int u, v, w, c;
		scanf("%d%d%d%d", &c, &w, &u, &v);
		qy[c].push_back(query(i, u, v, w, c));
	}
	cont (c, n) {
		if (!qy[c].size())  continue;
		solve(c);
	}
	cont (i, m) {
		printf("%d\n", ans[i]);
	}
}

Measured memory_bytes: 21136