#include<iostream>
#include<vector>
#include<algorithm>
#include<functional>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<unordered_map>
#include<climits>
#include<cstdlib>
#include<cmath>
#include<string>
#include<iomanip>
#include<bitset>
#include<list>

using namespace std;

#define ll long long int

ll const MOD = 1000000007;
ll const INF = (long long int)1 << 61;

ll mypow(ll x,ll n,ll mod = MOD){
    ll ret = 1;
    while(n > 0){
        if(n&1){
            ret = (ret*x)%mod;
        }
        x = (x*x)%mod;
        n >>= 1;
    }
    return ret;
}

ll mygcd(ll a,ll b){
    if(b == 0)return a;
    return mygcd(b,a%b);
}

ll twoPow(ll shiftNum){
    return (1LL << (shiftNum - 1));
}

void eulerTour(vector<tuple<ll,ll,ll>> &ev,vector<ll> &tv,vector<list<pair<ll,ll>>> &cv,int x,const vector<list<tuple<ll,ll,ll>>> &edge,vector<bool> &used,int depth){
    ev.push_back(make_tuple(x,depth,ev.size()));
    used[x] = true;
    for(auto itr = edge[x].begin(); itr != edge[x].end(); itr++){
        if(!used[get<0>(*itr)]){
            cv[get<1>(*itr)].push_back(make_pair(ev.size()-1,get<2>(*itr)));
            tv.push_back(get<2>(*itr));
            eulerTour(ev,tv,cv,get<0>(*itr),edge,used,depth+1);
            ev.push_back(make_tuple(x,depth,ev.size()));
            cv[get<1>(*itr)].push_back(make_pair(ev.size()-1,-get<2>(*itr)));
            tv.push_back(-get<2>(*itr));
        }
    }
}

#include<vector>
#include<functional>

template<typename dataType>
class SegmentTree{
    int dataSize;
    dataType initialVal;
    std::vector<dataType> tree;
    std::function<dataType(dataType,dataType)> addFunc;
    std::function<dataType(dataType,dataType)> extFunc;

    void internalUpdate(int pointedIndex){
        while(pointedIndex > 1){
            pointedIndex >>= 1;
            tree[pointedIndex] = extFunc(tree[pointedIndex*2],tree[pointedIndex*2+1]);
        }
    }

public:

    SegmentTree(int N, dataType init,
                function<dataType(dataType,dataType)> f1 = [](dataType a,dataType b)->dataType{return a+b;},
                function<dataType(dataType,dataType)> f2 = [](dataType a,dataType b)->dataType{return a+b;})
                :initialVal(init),addFunc(f1),extFunc(f2){
                    dataSize = 1;
                    while(dataSize < N){
                        dataSize *= 2;
                    }
                    tree = std::vector<dataType>(dataSize*2,initialVal);
                }

    void initialize(vector<dataType> data){
        for(int i = dataSize; i < dataSize*2 && i - dataSize < data.size(); i++){
            tree[i] = data[i - dataSize];
        }
        for(int i = dataSize - 1; i > 0; i--){
            tree[i] = extFunc(tree[i*2],tree[i*2+1]);
        }
    }

    bool updateQuery(int index,dataType newVal){
        if(index < 1 || index > dataSize){
            return false;
        }
        int pointedIndex = dataSize + index - 1;
        tree[pointedIndex] = newVal;
        internalUpdate(pointedIndex);
        return true;
    }

    bool addQuery(int index,dataType newVal){
        if(index < 1 || index > dataSize){
            return false;
        }
        int pointedIndex = dataSize + index - 1;
        tree[pointedIndex] = addFunc(tree[pointedIndex],newVal);
        internalUpdate(pointedIndex);
        return true;
    }

    dataType getQuery(int leftIndex , int rightIndex){
        if(leftIndex > rightIndex || leftIndex < 1 || rightIndex > dataSize){
            return initialVal;
        }else if(leftIndex == rightIndex){
            return tree[dataSize + leftIndex - 1];
        }

        int leftPointedIndex = dataSize + leftIndex - 1;
        int rightPointedIndex = dataSize + rightIndex - 1;

        dataType leftVal = tree[leftPointedIndex];
        dataType rightVal = tree[rightPointedIndex];
        
        while(true){
            bool wasLeftEven = (leftPointedIndex % 2 == 0);
            bool wasRightEven = (rightPointedIndex % 2 == 0);

            leftPointedIndex >>= 1;
            rightPointedIndex >>= 1;

            if(leftPointedIndex == rightPointedIndex){
                return extFunc(leftVal,rightVal);
            }

            if(wasLeftEven){
                leftVal = extFunc(leftVal,tree[leftPointedIndex*2 + 1]);
            }

            if(!wasRightEven){
                rightVal = extFunc(rightVal,tree[rightPointedIndex*2]);
            }
        }

        return initialVal;
    }
};

int main(){
    cin.tie(0);
    ios::sync_with_stdio(false);
 
    ll n,q;
    cin >> n >> q;

    vector<ll> a(n),b(n),c(n),d(n);
    vector<list<tuple<ll,ll,ll>>> edge(n+1);

    for(int i = 0; i < n-1; i++){
        cin >> a[i] >> b[i] >> c[i] >> d[i];
        edge[a[i]].push_back(make_tuple(b[i],c[i],d[i]));
        edge[b[i]].push_back(make_tuple(a[i],c[i],d[i]));
    }

    vector<ll> x(q),y(q),u(q),v(q);
    for(int i = 0; i < q; i++){
        cin >> x[i] >> y[i] >> u[i] >> v[i];
    }

    vector<tuple<ll,ll,ll>> ev;
    vector<list<pair<ll,ll>>> cv(n+1);
    vector<ll> tv;
    vector<bool> used(n+1,false);

    eulerTour(ev,tv,cv,1,edge,used,1);

    auto f1 = [](pair<ll,ll> a,pair<ll,ll> b)->pair<ll,ll>{
        if(a < b){
            return a;
        }else{
            return b;
        }
    };

    auto f2 = [](pair<ll,ll> a,pair<ll,ll> b)->pair<ll,ll>{
        return make_pair(a.first + b.first,a.second);
    };

    SegmentTree<pair<ll,ll>> st(ev.size(),make_pair(INF,INF),f2,f1);
    for(int i = 0; i < ev.size(); i++){
        st.updateQuery(i+1,make_pair(get<1>(ev[i]),get<0>(ev[i])));
        /*cerr << st.getQuery(i+1,i+1).first << "\t";
        cerr << st.getQuery(i+1,i+1).second << endl;*/
    }

    for(int i = 0; i < ev.size(); i++){
        /*cerr << get<0>(ev[i]) << "\t";
        cerr << get<1>(ev[i]) << "\t";
        cerr << get<2>(ev[i]) << endl;*/
    }

    sort(ev.begin(),ev.end());

    vector<ll> sumt(tv.size()+1,0);

    for(int i = 1; i <= tv.size(); i++){
        sumt[i] = sumt[i-1] + tv[i-1];
    }

    vector<vector<tuple<ll,ll,ll>>> sumc;
    for(int i = 0; i < cv.size(); i++){
        vector<tuple<ll,ll,ll>> tmpsum;
        tmpsum.push_back(make_tuple(-1,0,0));
        for(auto itr = cv[i].begin(); itr != cv[i].end(); itr++){
            tmpsum.push_back(make_tuple((*itr).first,get<1>(tmpsum.back()) + (*itr).second,
            get<2>(tmpsum.back()) + ((*itr).second < 0 ? -1 : 1)));
        }
        sumc.push_back(tmpsum);
    }

    auto lca = [&](ll node1,ll node2)->pair<ll,ll>{
        auto low1 = lower_bound(ev.begin(),ev.end(),make_tuple(node1,0LL,0LL));
        auto low2 = lower_bound(ev.begin(),ev.end(),make_tuple(node2,0LL,0LL));
        auto upp1 = upper_bound(ev.begin(),ev.end(),make_tuple(node1,INF,INF));
        auto upp2 = upper_bound(ev.begin(),ev.end(),make_tuple(node2,INF,INF));
        ll lowIdx = min(get<2>(*low1),get<2>(*low2));
        ll uppIdx = max(get<2>(*(--upp1)),get<2>(*(--upp2)));
        auto ret = st.getQuery(lowIdx+1,uppIdx+1);
        return ret;
    };

    for(int i = 0; i < q; i++){
        auto low1 = lower_bound(ev.begin(),ev.end(),make_tuple(u[i],0LL,0LL));
        auto low2 = lower_bound(ev.begin(),ev.end(),make_tuple(v[i],0LL,0LL));
        auto ret = lca(u[i],v[i]);
        auto low3 = lower_bound(ev.begin(),ev.end(),make_tuple(ret.second,0LL,0LL));
        /*cerr << get<0>(*low3) << "\t";
        cerr << get<1>(*low3) << endl;
        cerr << get<2>(*low1) << "\t";
        cerr << get<2>(*low2) << "\t";
        cerr << get<2>(*low3) << endl;*/
        ll dist1 = sumt[get<2>(*low1)];
        ll dist2 = sumt[get<2>(*low2)];
        ll dist3 = sumt[get<2>(*low3)];
        ll totaldist = dist1 + dist2 - 2*dist3;
        auto upp1 = upper_bound(sumc[x[i]].begin(),sumc[x[i]].end(),make_tuple(get<2>(*low1),0,0));
        auto upp2 = upper_bound(sumc[x[i]].begin(),sumc[x[i]].end(),make_tuple(get<2>(*low2),0,0));
        auto upp3 = upper_bound(sumc[x[i]].begin(),sumc[x[i]].end(),make_tuple(get<2>(*low3),0,0));
        ll cdist1 = get<1>(*(--upp1));
        ll cdist2 = get<1>(*(--upp2));
        ll cdist3 = get<1>(*(--upp3));
        /*cerr << cdist1 << "\t";
        cerr << cdist2 << "\t";
        cerr << cdist3 << endl;*/
        ll rev = cdist1 + cdist2 - 2*cdist3;
        ll cnum1 = get<2>(*(upp1));
        ll cnum2 = get<2>(*(upp2));
        ll cnum3 = get<2>(*(upp3));
        ll num = cnum1 + cnum2 - 2*cnum3;

        cout << totaldist - rev + num*y[i] << endl;
    }

    return 0;
}

Measured memory_bytes: 68448