#include <bits/stdc++.h>
#define rep(i,n) for(int i=0;i<(int)(n);i++)
#define rep1(i,n) for(int i=1;i<=(int)(n);i++)
#define all(c) c.begin(),c.end()
#define pb push_back
#define fs first
#define sc second
#define chmin(x,y) x=min(x,y)
#define chmax(x,y) x=max(x,y)
using namespace std;
template<class S,class T> ostream& operator<<(ostream& o,const pair<S,T> &p){
	return o<<"("<<p.fs<<","<<p.sc<<")";
}
template<class T> ostream& operator<<(ostream& o,const vector<T> &vc){
	o<<"{";
	for(const T& v:vc) o<<v<<",";
	o<<"}";
	return o;
}
using ll = long long;
template<class T> using V = vector<T>;
template<class T> using VV = vector<vector<T>>;
constexpr ll TEN(int n) { return (n == 0) ? 1 : 10 * TEN(n-1); }

#ifdef LOCAL
#define show(x) cerr << "LINE" << __LINE__ << " : " << #x << " = " << (x) << endl
#else
#define show(x) true
#endif

template<class D>
struct segtree_simple{
	int N;
	vector<D> val;

	segtree_simple(){}
	segtree_simple(int n){
		N=1;
		while(N<n) N*=2;
		val.assign(N*2,D::e());
	}
	segtree_simple(const vector<D>& ds){
		int n = ds.size();
		N=1;
		while(N<n) N*=2;
		val.assign(N*2,D::e());
		rep(i,n) val[i+N] = ds[i];
		for(int i=N-1;i>0;i--) val[i] = val[i*2] + val[i*2+1];
	}
	void assign(int k,D d){
		k+=N;
		val[k]=d;
		k/=2;
		while(k){
			val[k] = val[k*2] + val[k*2+1];
			k/=2;
		}
	}
	D query(int a,int b){		//non-commutative & unrecursive
		D L = D::e() , R = D::e();
		a+=N,b+=N;
		while(a<b){
			if(a&1) L = L + val[a++];
			if(b&1) R = val[--b] + R;
			a/=2,b/=2;
		}
		return L+R;
	}
};

template<class E, class D>		//for simple segtree
struct HLdecomp{
	using segtree = segtree_simple<D>;

	static const bool OnEdge = 1;

	vector<vector<E>> G;
	using P = pair<int,int>;
	vector<P> id;				//id[v] = P(chain_id,pos_on_chain)	posはtop to bottom
	vector<int> sz;				//sz[v] = subtree_size
	vector<int> dep;			//dep[v] = depth
	vector<int> par;			//par[v] = parent
	vector<int> top;			//id[v].fs の一番上

	int C;	//num of chains
	vector<vector<int>> chains;	//chains[c][i] = v <=> id[v] = P(c,i)
	vector<segtree> segs;

	HLdecomp(const vector<vector<E>>& G, int r = 0):G(G){
		int N = G.size();
		C = 1;
		chains.pb({0});
		id.assign(N,P(0,0));
		sz.assign(N,0);
		dep.assign(N,0);
		par.assign(N,0);
		top.assign(N,0);

		dfs_base(r);
		dfs_decomp(r);

	
		rep(c,C) segs.pb(segtree(chains[c].size()));
	}
	void dfs_base(int v,int p=-1){	//calc sz,dep
		sz[v] = 1;
		par[v] = p;
		if(p==-1) dep[v] = 0;
		else dep[v] = dep[p] + 1;
		for(const auto& e: G[v]){
			int u = e.to;
			if(u==p) continue;
			dfs_base(u,v);
			sz[v] += sz[u];
		}
	}
	void dfs_decomp(int v,int p=-1){
		int heavy = -1;
		for(const auto& e: G[v]){
			int u = e.to;
			if(u == p) continue;
			if(heavy == -1 || sz[heavy]<sz[u]) heavy = u;
		}
		for(const auto& e: G[v]){
			int u = e.to;
			if(u == p) continue;
			if(u == heavy){
				id[u] = P(id[v].fs,id[v].sc+1);
				top[u] = top[v];
			}else{
				id[u] = P(C,0);
				top[u] = u;
				C++;
				chains.pb({});
			}
			chains[id[u].fs].pb(u);
			dfs_decomp(u,v);
		}
	}
	int lca(int a,int b){
		while(id[a].fs != id[b].fs){
			if(id[a].fs < id[b].fs) b = par[top[b]];
			else a = par[top[a]];
		}
		return dep[a]<dep[b] ? a : b;
	}
	int up(int v,int d){	//vから上にd上がった点
		if(dep[v]<d) return -1;
		while(true){
			int d1 = dep[v] - dep[top[v]];
			if(d1<=d){
				d -= d1;
				v = top[v];
			}else{
				int c = id[v].fs;
				return chains[c][d1-d];
			}
			if(d==0) return v;
			v = par[v];
			d--;
		}
		assert(0);
		return -1;
	}
	D query(int u,int v){	//[u,w) + [w,v]			edge ver なら [u,w) + (w,v]
		int w = lca(u,v);
		D up,down;

		{
			for(;id[u].fs!=id[w].fs; u = par[top[u]]){
				//chains[c][l,r]
				int c = id[u].fs;
				int l = id[top[u]].sc;
				int r = id[u].sc;
				D x = segs[c].query(l,r+1);
				up = x + up;
			}
			int c = id[u].fs;
			int l = id[w].sc+1;
			int r = id[u].sc;
			D x = segs[c].query(l,r+1);
			up = x + up;
		}
		{
			u = v;
			for(;id[u].fs!=id[w].fs; u = par[top[u]]){
				int c = id[u].fs;
				int l = id[top[u]].sc;
				int r = id[u].sc;
				D x = segs[c].query(l,r+1);
				down = x + down;
			}
			int c = id[u].fs;
			int l = id[w].sc + OnEdge;
			int r = id[u].sc;
			D x = segs[c].query(l,r+1);
			down = x + down;
		}

		// ! reverse up !
		return up + down;
	}

	// Vertex version
	// d[v] <= x
	void assign(int v,const D &x){
		int c = id[v].fs;
		int i = id[v].sc;
		segs[c].assign(i,x);
	}
	// Edge version
	// d[(v,u)] <= x
	void assign(int v,int u,const D &x){
		if(dep[v] < dep[u]) swap(v,u);
		assert(dep[v] == dep[u]+1);
		int c = id[v].fs;
		int i = id[v].sc;
		segs[c].assign(i,x);
	}
};

struct D{
	int x;
	D(){*this = e();}
	D(int x):x(x){}
	static D e(){
		return D(0);
	}
	D operator+(const D& r) const {
		return D(x+r.x);
	}
};


int main(){
	cin.tie(0);
	ios::sync_with_stdio(false);		//DON'T USE scanf/printf/puts !!
	cout << fixed << setprecision(20);
	
	int N,Q;
	cin >> N >> Q;
	struct E{
		int from,to,c,d;
		E(int from_,int to_,int c_,int d_):from(from_),to(to_),c(c_),d(d_){}
	};
	VV<E> G(N);
	V<E> es;
	rep(i,N-1){
		int a,b,c,d;
		cin >> a >> b >> c >> d;
		a--,b--;
		G[a].emplace_back(a,b,c,d);
		G[b].emplace_back(b,a,c,d);
		es.emplace_back(a,b,c,d);
	}
	HLdecomp<E,D> HLD(G);

	V<int> x(Q),y(Q),u(Q),v(Q);
	VV<int> c2qs(N);
	VV<E> c2es(N);
	rep(q,Q){
		cin >> x[q] >> y[q] >> u[q] >> v[q];
		u[q]--,v[q]--;
		c2qs[x[q]].pb(q);
	}
	for(auto e: es){
		c2es[e.c].pb(e);
	}

	for(auto e: es){
		HLD.assign(e.from,e.to,D(e.d));
	}
	V<int> ans(Q);
	rep(c,N){
		show(c);
		for(auto e: c2es[c]){
			HLD.assign(e.from,e.to,D(0));
		}
		V<int> w0,w1;
		for(int q: c2qs[c]){
			w0.pb(HLD.query(u[q],v[q]).x);
		}
		for(auto e: c2es[c]){
			HLD.assign(e.from,e.to,D(1));
		}
		for(int q: c2qs[c]){
			w1.pb(HLD.query(u[q],v[q]).x);
		}
		for(auto e: c2es[c]){
			HLD.assign(e.from,e.to,D(e.d));
		}
		rep(i,c2qs[c].size()){
			int q = c2qs[c][i];
			ans[q] = w0[i] + (w1[i]-w0[i]) * y[q];
		}
	}
	rep(q,Q){
		cout << ans[q] << endl;
	}
}


Measured memory_bytes: 42216