#include <iostream>
#include <string>
#include <vector>
#include <set>
#include <algorithm>
#include <cctype>
#include <cmath>
#include <queue>
#include <map>
#include <numeric>
#include <unordered_map>
#include <iomanip>
#include <functional>
#include <bitset>
#include <complex>
#include <stack>



#define rep(i, n) for(int i = 0; i < (int)(n); i++)
#define rrep(i, n) for(int i = (int)(n-1); i >= 0; i--)
#define repi(i,a,b) for(int i=int(a);i<int(b);i++)
#define all(x) (x).begin(),(x).end()

template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return 1; } return 0; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return 1; } return 0; }

typedef long long ll;

using namespace std;



template< typename T >
struct SparseTable {
  vector< vector< T > > st;
  vector< int > lookup;

  SparseTable(const vector< T > &v) {
    int b = 0;
    while((1 << b) <= v.size()) ++b;
    st.assign(b, vector< T >(1 << b));
    for(int i = 0; i < v.size(); i++) {
      st[0][i] = v[i];
    }
    for(int i = 1; i < b; i++) {
      for(int j = 0; j + (1 << i) <= (1 << b); j++) {
        st[i][j] = min(st[i - 1][j], st[i - 1][j + (1 << (i - 1))]);
      }
    }
    lookup.resize(v.size() + 1);
    for(int i = 2; i < lookup.size(); i++) {
      lookup[i] = lookup[i >> 1] + 1;
    }
  }

  inline T rmq(int l, int r) {
    int b = lookup[r - l];
    return min(st[b][l], st[b][r - (1 << b)]);
  }
};

template <class Monoid>
class SegmentTree
{
public:
  using Func = function<Monoid(Monoid, Monoid)>;
  const Func F;
  const Monoid M1;
  int sz;
  vector<Monoid> seg;

  SegmentTree(int n,const Func fu, const Monoid &m1): F(fu) , M1(m1) {init(n);}
  void init(int n)
  {
      sz= 1;
      while (sz < n) sz *= 2;
      seg.assign(sz * 2, M1);
  }
  void update(int k,const Monoid &x)
  {
    k+=sz;
    seg[k]=x;
    while(k>>=1)
    {
      seg[k]=F(seg[k*2],seg[k*2+1]);
    }
  }
  Monoid query(int l,int r)
  {
    Monoid L=M1,R=M1;
    l+=sz;r+=sz;
    for(;l<r;l>>=1,r>>=1)
    {
      if(l&1)L=F(L,seg[l++]);
      if(r&1)R=F(seg[--r],R);
    }
    return F(L,R);
  }
};
int main()
{
  ios::sync_with_stdio(false);
  cin.tie(0);
  ll n,q;cin>>n>>q;
  struct edge{
    ll from,to,col,dis;
  };
  vector<vector<edge>>ed(n);
  rep(i,n-1){
    ll a,b,c,d;cin>>a>>b>>c>>d;
    a--;b--;
    c--;
    ed[a].push_back({a,b,c,d});
    ed[b].push_back({b,a,c,d});
  }
  vector<ll>dep(n);
  vector<ll>eular;
  vector<pair<ll,ll>>eular2;
  vector<ll>ds(n),us(n);
  vector<vector<ll>>coled(n);
  ds[0]=-1;
  vector<ll>e1(n);
  vector<pair<ll,ll>>e;
  function<void(ll,ll,ll)> dfs2=[&](ll no,ll pr,ll d){
    e1[no]=e.size();
    for(auto nn:ed[no]){
      if(nn.to==pr)continue;
      e.push_back({d,no});
      dfs2(nn.to,no,d+1);
    }
    e.push_back({d,no});
  };
  function<void(ll,ll,ll,ll&)>dfs=[&](ll no,ll pr,ll d,ll &idx){
    dep[no]=d;
    for(auto nn:ed[no]){
      if(nn.to==pr)continue;
      eular.push_back(nn.dis);
      coled[nn.col].push_back(idx);
      ds[nn.to]=idx++;
      dfs(nn.to,no,d+1,idx);


      eular.push_back(-nn.dis);
      coled[nn.col].push_back(idx);
      us[nn.to]=idx++;

    }


  };
  ll id=0;
  dfs(0,-1,0,id);
  dfs2(0,-1,0);
  SegmentTree<pair<ll,ll>>st(e.size()+7,[](pair<ll,ll> a,pair<ll,ll> b){return min(a,b);},{1e9,1e9});
  rep(i,e.size()){
    st.update(i,e[i]);
    ////cout<<e[i].first<<" "<<e[i].second<<endl;
  }
  auto lca=[&](ll s,ll t){
    if(e1[s]>e1[t])swap(s,t);
    return st.query(e1[s],e1[t]+1).second;
  };
  struct query{
    ll c,y,u,v,id;
    void print(){
      ////cout<<"id "<<id<<" "<<u<<" "<<v<<endl;
    }
  };
  vector<vector<query>>qs(n);
  rep(i,q){
    ll a,b,c,d;cin>>a>>b>>c>>d;
    a--;c--;d--;
    qs[a].push_back({a,b,c,d,i});
  }
  vector<ll>se(2*n);
  rep(i,2*n-1){
    se[i+1]=eular[i]+se[i];
  }
  auto caldist=[&](ll v){
    ////cout<<ds[v]+1<<endl;
    if(v==0)return 0LL;
    return se[ds[v]+1];
  };
  SegmentTree<ll>te1(2*n,[](ll a,ll b){return a+b;},0);
  auto te2=te1;
  vector<ll>res(q);
  rep(i,n){
    for(auto j:coled[i]){
      if(eular[j]>=0){
        te1.update(j,eular[j]);
        te2.update(j,1);
      }
      else {
          te1.update(j,eular[j]);
          te2.update(j,-1);
      }
    }
    for(auto tq:qs[i]){
      ll lc=lca(tq.u,tq.v);
      ////cout<<" lca"<<lc<<endl;
      ll td=caldist(tq.u)+caldist(tq.v)-2*caldist(lc);

      tq.print();
      ////cout<<"cald "<<caldist(tq.v)<<" "<<caldist(tq.u)<<endl;
      ////cout<<"lca "<<lc<<endl;
      ////cout<<td<<" ";
      td-=te1.query(0,ds[tq.u]+1)+te1.query(0,ds[tq.v]+1)-2*te1.query(0,ds[lc]+1);
      ////cout<<td<<" ";

      td+=(te2.query(0,ds[tq.u]+1)+te2.query(0,ds[tq.v]+1)-2*te2.query(0,ds[lc]+1))*tq.y;
      ////cout<<td<<" ";
      ////cout<<endl;
      res[tq.id]=td;
    }
    for(auto j:coled[i]){
      te1.update(j,0);
      te2.update(j,0);
    }
  }
  rep(i,q){
    cout<<res[i]<<endl;
  }




}


Measured memory_bytes: 60472