#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;

namespace io {
	#define isdigit(c)  (c >= '0' && c <= '9')
	#define getchar()   (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, bufsz, stdin), p1 == p2) ? EOF : *p1++)
	#define flush()     (fwrite(puf, 1, pp - puf, stdout), pp = puf)
	#define putchar(c)  (*pp++ = c, pp - puf == bufsz && flush())
	
	const int bufsz = 1 << 24;
	static char buf[bufsz], puf[bufsz], *p1, *p2, *pp = puf;
	struct flusher { ~flusher() { flush(); } } flusher;
	
	template<class type>
	void inline read(type &a) {
		int f = 1, c = getchar();
		for (; !isdigit(c); c == 45 && (f = -1), c = getchar());
		for (a = 0; isdigit(c); a *= 10, a += c & 15, c = getchar());
		a *= f;
	}
	
	template<class type>
	void inline write(type a, char c = ln) {
		static int d[20];
		int s = d[0] = 0;
		for (a < 0 && (putchar(45), a = -a); a; d[s++] = a % 10, a /= 10);
		for (s || (s = 1); s; putchar(d[--s] + 48));
		putchar(c);
	}
}
using namespace io;

const int nsz = int(1e5), trsz = 2 * nsz;
int n, m, ans[nsz + 5];

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;

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

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

void inline solve(int c) {
	loop (i, e[c].size()) {
		int u = e[c][i].u, v = e[c][i].v, w = e[c][i].w, id = e[c][i].id;
		tr.set(id, 1, 0);
	}
	
	loop (i, qy[c].size()) {
		int qu = qy[c][i].u, qv = qy[c][i].v, w = qy[c][i].w, id = qy[c][i].id;
		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].u, v = e[c][i].v, w = e[c][i].w, id = e[c][i].id;
		tr.set(id, 0, w);
	}
}

int main() {
	read(n), read(m);
	cont (i, n)  tr.node();
	cont (i, n - 1) {
		int u, v, c, w;
		read(u), read(v), read(c), read(w);
		link(u, v, w);
		e[c].push_back(data(u, v, w, tr.sz));
	}
	cont (i, m) {
		int u, v, c, w;
		read(c), read(w), read(u), read(v);
		qy[c].push_back(data(u, v, w, i));
	}
	
	cont (c, n - 1) {
		solve(c);
	}
	
	cont (i, m) {
		write(ans[i]);
	}
}

Measured memory_bytes: 24048