#pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/tag_and_trait.hpp>
#include <ext/pb_ds/trie_policy.hpp>

using namespace __gnu_pbds;
using namespace std;

#define rep(i,n) for(int i=0;i<(n);++i)
#define reps(i,n) for(int i=1;i<=(n);++i)
#define all(x) (x).begin(),(x).end()
#define Fixed fixed << setprecision(12)
#define int int_fast64_t
using pii = pair<int,int>;
constexpr int INF  = 0x3f3f3f3f;
constexpr long long LINF = 0x3f3f3f3f3f3f3f3fLL;
constexpr int mod1 = 1e9+7;
constexpr int mod2 = 998244353;

template <class Func>
class FixPoint : Func {
public:
    explicit constexpr FixPoint(Func&& f) noexcept : Func(forward<Func>(f)) {}

    template <class... Args>
    constexpr decltype(auto) operator()(Args&&... args) const {
        return Func::operator()(*this, std::forward<Args>(args)...);
    }
};

template <class Func>
static inline constexpr decltype(auto) makeFixPoint(Func&& f) noexcept {
    return FixPoint<Func>{forward<Func>(f)};
}

template <class A, class B> inline bool chmax(A &a, const B &b) { return b > a && (a = b, true); }
template <class A, class B> inline bool chmin(A &a, const B &b) { return b < a && (a = b, true); }

template <class T> using min_heap = priority_queue<T,vector<T>,greater<T> >;
template <class T> using max_heap = priority_queue<T>;
template <class A, class B> using umap = unordered_map<A,B>;
template <class T> using Set = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;
template <class K, class V> using Umap = gp_hash_table<K, V>;
using Trie = trie<string, null_type, trie_string_access_traits<>, pat_trie_tag, trie_prefix_search_node_update>;

inline int square(int a){ return a * a;}
inline int updiv(int a,int b){ return (a + b - 1) / b; }

constexpr int dx[] = {1,0,-1,0,1,1,-1,-1};
constexpr int dy[] = {0,-1,0,1,1,-1,-1,1};

struct Mo
{
    vector<int> left, right, order;
    vector<bool> v;
    int width;
    int nl, nr, ptr;

    // left     : クエリの左端
    // right    : クエリの右端
    // order    : クエリの実行順
    // v        : 要素を追加してあればtrueしてなければfalse
    // width    : 分割するブロックの長さ(sqrt(n))
    // nl       : 追加したものの左端
    // nr       : 追加したものの右端+1
    // ptr      : 現在のクエリ番号(order)

    Mo(int n) : width((int) sqrt(n)), nl(0), nr(0), ptr(0), v(n) {}

    /* クエリの追加 [l, r) */
    void insert(int l, int r){
        left.emplace_back(l);
        right.emplace_back(r);
    }

    /* ソート */
    void build(){
        order.resize(left.size());
        iota(begin(order), end(order), 0);
        // クエリの左端が属するブロックの昇順でソート
        // 左端が同じグループなら右端の値でソート
        sort(begin(order), end(order), [&](int a, int b){
            int ablock = left[a] / width, bblock = left[b] / width;
            if(ablock != bblock) return (ablock < bblock);
            if(ablock & 1) return (right[a] < right[b]);
            return (right[a] > right[b]);
        });
    } 
    
    /* 全てのクエリの実行 */
    template<typename ADD, typename DEL, typename REM>
    void run(const ADD &add, const DEL &del, const REM &rem){
        /* クエリの伸縮 */
        auto distribute = [&](int idx){
            v[idx].flip();
            if(v[idx]) add(idx);
            else del(idx);
        };
        /* クエリを１つ分進めてクエリのidを返す */
        auto process = [&](){
            if(ptr == order.size()) return; // クエリの終端
            const auto id = order[ptr]; // クエリのid
            while(nl > left[id]) distribute(--nl); // 左端をクエリの左端に合うように調整(左に)
            while(nr < right[id]) distribute(nr++); // 右端をクエリの右端に合うように調整(右に)
            while(nl < left[id]) distribute(nl++); // 左端をクエリの左端に合うように調整(右に)
            while(nr > right[id]) distribute(--nr); // 右端をクエリの右端に合うように調整(左に)
            ptr++; // クエリのidを返し、クエリを１つ進める
        };

        build();
        for(auto idx : order){
            process();
            rem(idx);
        }
        return;
    }
};

template< typename T >
struct BinaryIndexedTree {
  vector< T > data;

  BinaryIndexedTree(int sz) {
    data.assign(++sz, 0);
  }

  T sum(int k) {
    T ret = 0;
    for(++k; k > 0; k -= k & -k) ret += data[k];
    return (ret);
  }

  void add(int k, T x) {
    for(++k; k < data.size(); k += k & -k) data[k] += x;
  }
};

vector<vector<tuple<int, int, int> > > graph;
vector<int> v;
void dfs(int now, int par){
    v.emplace_back(now);
    for(auto [to, c, d] : graph[now]){
        if(to != par){
            dfs(to, now);
            v.emplace_back(now);
        }
    }
    return;
}

signed main(){
    cin.tie(nullptr);
    ios_base::sync_with_stdio(false);
    cout.setf(ios_base::fixed);
    cout.precision(10);

    int n, q;
    cin >> n >> q;

    graph.resize(n);
    vector<tuple<int, int, int, int> > edge;
    map<pii, int> to_idx;

    rep(i,n-1){
        int a, b, c, d;
        cin >> a >> b >> c >> d;
        --a, --b;
        graph[a].emplace_back(b, c, d);
        graph[b].emplace_back(a, c, d);
        edge.emplace_back(a, b, c, d);
        to_idx[minmax(a, b)] = i;
    }

    dfs(0,-1);

    vector<int> fp(n, INF);
    vector<int> edge_idx;

    rep(i,v.size()-1){
        edge_idx.emplace_back(to_idx[minmax(v[i], v[i+1])]);
    }

    rep(i,v.size()){
        chmin(fp[v[i]], i);
    }

    Mo mo(edge_idx.size());
    vector<int> color_sum(1e5+1);
    vector<bool> added(n);
    int sum = 0;
    vector<int> cnt(1e5+1);
    vector<int> x(q), y(q), u(q), v(q);

    rep(i,q){
        cin >> x[i] >> y[i] >> u[i] >> v[i];
        --u[i], --v[i];
        auto [l, r] = minmax(fp[u[i]], fp[v[i]]);
        mo.insert(l, r);
    }

    auto add = [&](int k){
        k = edge_idx[k];
        added[k].flip();
        if(added[k]){
            sum += get<3>(edge[k]);
            ++cnt[get<2>(edge[k])];
            color_sum[get<2>(edge[k])] += get<3>(edge[k]);
        }else{
            sum -= get<3>(edge[k]);
            --cnt[get<2>(edge[k])];
            color_sum[get<2>(edge[k])] -= get<3>(edge[k]);
        }
    };
    auto del = [&](int k){
        k = edge_idx[k];
        added[k].flip();
        if(added[k]){
            sum += get<3>(edge[k]);
            ++cnt[get<2>(edge[k])];
            color_sum[get<2>(edge[k])] += get<3>(edge[k]);
        }else{
            sum -= get<3>(edge[k]);
            --cnt[get<2>(edge[k])];
            color_sum[get<2>(edge[k])] -= get<3>(edge[k]);
        }
    };
    vector<int> res(q);
    auto rem = [&](int k){
        res[k] = sum - color_sum[x[k]] + cnt[x[k]] * y[k];
    };
    mo.run(add, del, rem);

    for(auto&& e : res){
        cout << e << '\n';
    }

    return 0;
}

Measured memory_bytes: 40912