#include<bits/stdc++.h>
using namespace std;
#define REP(i,n) for(long long i=0;i<n;i++)
#define REP1(i,n) for(long long i=1;i<=n;i++)
#define REP2D(i,j,h,w) for(long long i=0;i<h;i++) for(long long j=0;j<w;j++)
#define REP2D1(i,j,h,w) for(long long i=1;i<=h;i++) for(long long j=1;j<=w;j++)
#define PER(i,n) for(long long i=((n)-1);i>=0;i--)
#define PER1(i,n) for(long long i=(n);i>0;i--)
#define FOR(i,a,b) for(long long i=(a);i<(b);i++)
#define FORE(i,a,b) for(long long i=(a);i<=(b);i++)
#define ITE(arr) for(auto ite=(arr).begin();ite!=(arr).end();++ite)
#define ALL(a) (a.begin()),(a.end())
#define RANGE(a) (a),(a+sizeof(a))
#define ZERO(a) memset(a,0,sizeof(a))
#define MINUS(a) memset(a,0xff,sizeof(a))
#define YNPRT(b) cout<<((b)?"Yes":"No")<<endl
#define REV(arr) reverse(ALL(arr))
#define PRT(a) cout<<a<<endl;
#define PRTLST(arr,num) REP(_i,num) cout<<_i<<" - "<<arr[_i]<<endl;
#define PRTLST2(arr2,d1,d2) REP(_i,d1) REP(_j,d2) cout<<_i<<","<<_j<<" : "<<arr2[_i][_j]<<endl;
#define PRTLST2D(arr2,d1,d2) do{cout<<"L\t";REP(_i,d2) cout<<_i<<"\t"; cout<<endl; REP(_i,d1){cout<<_i<<"\t";REP(_j,d2){cout<<arr2[_i][_j]<<"\t";}cout<<endl;}}while(0);
#define MIN(target,v1) (target)=min(target,v1)
#define MAX(target,v1) (target)=max(target,v1) 
#define P1 first
#define P2 second
#define PB push_back
#define UB upper_bound
#define LB lower_bound
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const int INF_INT = 2147483647;
const ll INF_LL = 9223372036854775807LL;
const ull INF_ULL = 18446744073709551615Ull;
const ll P = 92540646808111039LL;
const int Move[4][2] = {-1,0,0,1,1,0,0,-1};
const int Move_[8][2] = {-1,0,-1,-1,0,1,1,1,1,0,1,-1,0,-1,-1,-1};
template<typename T1,typename T2>
ostream& operator<<(ostream& os,const pair<T1,T2>& p) {os<<"( "<<p.P1<<" , "<<p.P2<<" )";return os;}
template<typename T>
ostream& operator<<(ostream& os,const vector<T>& v) {ITE(v) os << (ite-v.begin()) << " : " << *ite <<endl;return os;}
template<typename T>
ostream& operator<<(ostream& os,const set<T>& v) {os<<" { ";ITE(v) {os<<*ite;if(ite!=--v.end()){os<<" , ";}} os<<" } ";return os;}
template<typename T1,typename T2>
ostream& operator<<(ostream& os,const map<T1,T2>& m) {ITE(m) {os<<ite->P1<<"\t\t|->\t\t"<<ite->P2<<endl;} return os;}

//---------------------
#define MAXN 100005
//---------------------

//==================UF======================
#define MAXUF 100005
typedef ll uf_val;
//---------------------
uf_val uf_par[MAXUF];
ll uf_rank[MAXUF];

void uf_init(){ // Initialize Union-find set
	REP(i,MAXUF){
		uf_par[i]=uf_val(i);
		uf_rank[i]=1;
	}
}

uf_val uf_find(const uf_val& a){ // Find parent
	return (uf_par[a]==a)?(a):(uf_par[a]=uf_find(uf_par[a])); // Compress path
}

void uf_unite(const uf_val& a, const uf_val& b){
	auto x = uf_find(a), y = uf_find(b);
	if(x==y) return;
	uf_par[y]=x;
	//if (uf_rank[x]<uf_rank[y]) {uf_par[x]=y; uf_rank[y]+=uf_rank[x];}
	//else {uf_par[y]=x; uf_rank[x]+=uf_rank[y];}
}

bool uf_same(const uf_val& a,const uf_val& b){
	return uf_find(a) == uf_find(b);
}

//==================UF======================

struct edge{
	int v;
	int c;
	int d;
};

struct ques{
	int x,y,u,v;
};

struct vexdata{
	int dist;
	int num;
};

ques qlist[MAXN];
vector<edge> G[MAXN];
map<int,vexdata> vlist[MAXN];


map<pii,int> LCF;
bool LCFfound[MAXN];
vector<int> vqlist[MAXN];


int n,q;


int memdist;
int memCdist[MAXN];
int memCnum[MAXN];
void preIterate(int lastid, int curid){
  	ITE(vlist[curid]){
  	  	ite->second.dist=memCdist[ite->first];
  	  	ite->second.num=memCnum[ite->first];
  	}
  	vlist[curid][0].dist=memdist;
	ITE(G[curid]){
		if(ite->v==lastid) continue;
		
		memdist+=ite->d;
		memCdist[ite->c]+=ite->d;
		memCnum[ite->c]++;
		
		preIterate(curid,ite->v);
		
		memdist-=ite->d;
		memCdist[ite->c]-=ite->d;
		memCnum[ite->c]--;
	
	}
}

void doLCF(int lastid,int curid){
  	LCFfound[curid]=true;
  
	ITE(G[curid]){
		if(ite->v==lastid) continue;
		
		doLCF(curid,ite->v);	
		uf_unite(curid,ite->v);

	}
	
	
	ITE(vqlist[curid]){
	  	
		if(LCFfound[*ite]) {
			int tu=curid,tv=*ite;
			if(tu>=tv) swap(tu,tv);
			LCF[pii(tu,tv)]=uf_find(*ite);
		}
	}
}

void solve(){
  	REP(i,q){
  		int u=qlist[i].u,v=qlist[i].v,x=qlist[i].x,y=qlist[i].y;
  		if(u>=v) swap(u,v);
  		int f=LCF[pii(u,v)];
  		int res = vlist[u][0].dist+vlist[v][0].dist-2*vlist[f][0].dist;
		int resOrg=vlist[u][x].dist+vlist[v][x].dist-2*vlist[f][x].dist;
		int resNew=y*(vlist[u][x].num+vlist[v][x].num-2*vlist[f][x].num);
		cout<<res-resOrg+resNew<<endl;
  	}
}



int main(){
  	cin>>n>>q;
  	uf_init();
  	REP(i,n-1) {
  		int ta,tb,tc,td; 
  		cin>>ta>>tb>>tc>>td; 
  		G[ta].PB({tb,tc,td}); 
  		G[tb].PB({ta,tc,td});
  	}
  	REP(i,q){
  	  	int tx,ty,tu,tv;
  	  	cin>>tx>>ty>>tu>>tv;
  		qlist[i]=(ques){tx,ty,tu,tv};
  		vqlist[tu].PB(tv);
  		vqlist[tv].PB(tu);
  	}
  	ZERO(memCdist);ZERO(memCnum);
  	
  	REP(i,MAXN) LCFfound[i]=false;
  	doLCF(0,1);
  	
  	vexdata tempdata;
  	REP(i,q){
  	  	int tu=qlist[i].u ,tv=qlist[i].v ,tc=qlist[i].x;
  	  	if(tu>=tv) swap(tu,tv);
  		vlist[tu][tc]=tempdata;
		vlist[tv][tc]=tempdata;
		vlist[LCF[pii(tu,tv)]][tc]=tempdata;
  	}
  	
  	REP1(i,n) vlist[i][0]=tempdata;
  	preIterate(0,1);
  	
  	solve();
	return 0;
}

Measured memory_bytes: 52024