#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 = int(1e5), trsz = 2 * nsz;

struct link_cut_tree {
	#define dir(u)    (rs[pr[u]] == u)
	#define s(u, d)   (d ? rs[u] : ls[u])
	#define is_rt(u)  (ls[pr[u]] != u && rs[pr[u]] != u)
	
	bool rev[trsz + 5];
	int sz, pr[trsz + 5], ls[trsz + 5], rs[trsz + 5];
	int val[trsz + 5][2], sum[trsz + 5][2];
	
	int inline node(int w0 = 0, int w1 = 0) {
		int u = ++sz;
		pr[u] = ls[u] = rs[u] = rev[u] = 0;
		val[u][0] = sum[u][0] = w0;
		val[u][1] = sum[u][1] = w1;
		return u;
	}
	
	void inline up(int u) {
		int v1 = ls[u], v2 = rs[u];
		sum[u][0] = sum[v1][0] + sum[v2][0] + val[u][0];
		sum[u][1] = sum[v1][1] + sum[v2][1] + val[u][1];
	}
	
	void inline down(int u) {
		if (rev[u]) {
			int v1 = ls[u], v2 = rs[u];
			if (v1)  swap(ls[v1], rs[v1]), rev[v1] ^= 1;
			if (v2)  swap(ls[v2], rs[v2]), rev[v2] ^= 1;
			rev[u] = 0;
		}
	}
	
	void inline push_down(int u) {
		static int stk[trsz + 5];
		int s = 0;
		for (; !is_rt(u); stk[s++] = u, u = pr[u]);
		for (stk[s++] = u; s; down(stk[--s]));
	}
	
	void inline rotate(int u) {
		int p = pr[u], g = pr[p], d = dir(u), v = s(u, !d);
		!is_rt(p) && (s(g, dir(p)) = u); pr[u] = g;
		s(p, d) = v, pr[v] = p;
		s(u, !d) = p, pr[p] = u;
		up(p), up(u);
	}
	
	void inline splay(int u) {
		push_down(u);
		for (int p = pr[u]; !is_rt(u); rotate(u), p = pr[u]) {
			if (!is_rt(p))  rotate(dir(u) != dir(p) ? u : p);
		}
	}
	
	int inline access(int u) {
		int v = 0;
		for (; u; v = u, u = pr[u]) {
			splay(u);
			rs[u] = v, up(u);
		}
		return v;
	}
	
	void inline set_rt(int u) {
		access(u), splay(u);
		swap(ls[u], rs[u]), rev[u] ^= 1;
	}
	
	int inline rt_of(int u) {
		u = access(u);
		for (; ls[u]; down(u), u = ls[u]);
		splay(u);
		return u;
	}
	
	bool inline link(int u, int v) {
		set_rt(u);
		if (rt_of(v) == u)  return 0;
		splay(v);
		pr[u] = v, rs[v] = u;
		up(v);
		return 1;
	}
	
	bool inline cut(int u, int v) {
		set_rt(u), access(v), splay(v);
		if (ls[v] != u)  return 0;
		pr[u] = ls[v] = 0;
		up(v);
		return 1;
	}
	
	void inline set(int u, int w0, int w1) {
		splay(u);
		val[u][0] = w0, val[u][1] = w1;
		up(u);
	}
	
	int inline split(int u, int v) {
		set_rt(u), access(v), splay(v);
		return v;
	}
};
link_cut_tree tr;

int n, m, ans[nsz + 5];
vector< pair< pair<int, int>, int> > e[nsz + 5];
vector< pair< pair<int, int>, pair<int, int> > >qy[nsz + 5];
map< pair<int, int>, int> id;

void inline link(int u, int v, int w) {
	int e = tr.node(0, w);
	tr.link(u, e);
	tr.link(e, v);
	id[make_pair(u, v)] = e;
}

void inline solve(int c) {
	loop (i, e[c].size()) {
		int u = e[c][i].first.first, v = e[c][i].first.second, w = e[c][i].second;
		tr.set(id[make_pair(u, v)], 1, 0);
	}
	
	loop (i, qy[c].size()) {
		int qu = qy[c][i].first.first, qv = qy[c][i].first.second, w = qy[c][i].second.first, id = qy[c][i].second.second;
		int u = tr.split(qu, qv), cnt = tr.sum[u][0], sum = tr.sum[u][1];
		ans[id] = sum + cnt * w;
	}
	
	loop (i, e[c].size()) {
		int u = e[c][i].first.first, v = e[c][i].first.second, w = e[c][i].second;
		tr.set(id[make_pair(u, v)], 0, w);
	}
}

int main() {
	scanf("%d%d", &n, &m);
	cont (i, n) {
		tr.node();
	}
	cont (i, n - 1) {
		int u, v, c, w;
		scanf("%d%d%d%d", &u, &v, &c, &w);
		e[c].push_back(make_pair(make_pair(u, v), w));
		link(u, v, w);
	}
	cont (i, m) {
		int u, v, c, w;
		scanf("%d%d%d%d", &c, &w, &u, &v);
		qy[c].push_back(make_pair(make_pair(u, v), make_pair(w, i)));
	}
	cont (c, n - 1) {
		solve(c);
	}
	cont (i, m) {
		printf("%d\n", ans[i]);
	}
}

Measured memory_bytes: 22256