Problem:
Score : 600 points

Problem Statement

There is a tree with N vertices numbered 1 to N.
The i-th edge in this tree connects Vertex a_i and Vertex b_i, and the color and length of that edge are c_i and d_i, respectively.
Here the color of each edge is represented by an integer between 1 and N-1 (inclusive). The same integer corresponds to the same color, and different integers correspond to different colors.

Answer the following Q queries:

Query j (1 \leq j \leq Q): assuming that the length of every edge whose color is x_j is changed to y_j, find the distance between Vertex u_j and Vertex v_j. (The changes of the lengths of edges do not affect the subsequent queries.)

Constraints

2 \leq N \leq 10^5

1 \leq Q \leq 10^5

1 \leq a_i, b_i \leq N

1 \leq c_i \leq N-1

1 \leq d_i \leq 10^4

1 \leq x_j \leq N-1

1 \leq y_j \leq 10^4

1 \leq u_j < v_j \leq N

The given graph is a tree.

All values in input are integers.

Input

Input is given from Standard Input in the following format:

N Q
a_1 b_1 c_1 d_1
:
a_{N-1} b_{N-1} c_{N-1} d_{N-1}
x_1 y_1 u_1 v_1
:
x_Q y_Q u_Q v_Q

Output

Print Q lines. The j-th line (1 \leq j \leq Q) should contain the answer to Query j.

Sample Input 1

5 3
1 2 1 10
1 3 2 20
2 4 4 30
5 2 1 40
1 100 1 4
1 100 1 5
3 1000 3 4

Sample Output 1

130
200
60

The graph in this input is as follows:

Here the edges of Color 1 are shown as solid red lines, the edge of Color 2 is shown as a bold green line, and the edge of Color 4 is shown as a blue dashed line.

Query 1: Assuming that the length of every edge whose color is 1 is changed to 100, the distance between Vertex 1 and Vertex 4 is 100 + 30 = 130.

Query 2: Assuming that the length of every edge whose color is 1 is changed to 100, the distance between Vertex 1 and Vertex 5 is 100 + 100 = 200.

Query 3: Assuming that the length of every edge whose color is 3 is changed to 1000 (there is no such edge), the distance between Vertex 3 and Vertex 4 is 20 + 10 + 30 = 60. Note that the edges of Color 1 now have their original lengths.

Solution in C++14 (GCC 5.4.1) (judge verdict: Accepted)

#include <vector>
#include <stack>
#include <queue>
#include <list>
#include <bitset>
#include <set>
#include <map>
#include <unordered_set>
#include <unordered_map>
#include <algorithm>
#include <numeric>
#include <iostream>
#include <iomanip>
#include <string>
#include <chrono>
#include <random>
#include <cmath>
#include <cassert>
#include <climits>
#include <cstring>
#include <cstdlib>
#include <functional>
#include <sstream>

using namespace std;


struct Edge {
    Edge(int _u = -1, int _v = -1, int _c = 0, int _w = 0) : u(_u), v(_v), c(_c), w(_w) {
    }
    int u, v, c, w;
};

struct Query {
    Query(int _i = 0, int _x = 0, int _y = 0, int _u = 0, int _v = 0): x(_x), y(_y), u(_u), v(_v), id(_i) {
    }

    int id;
    int x, y;
    int u, v;
};

class Solution {
public:
    vector<long long> solve(int n, vector<Edge>& edges, vector<Query>& queries) {
        graph.clear();
        graph.resize(n);

        int h = 0;
        while (1 << (h + 1) <= n) {
            ++h;
        }
        pars.clear();
        pars.resize(n, vector<int>(h + 1, -1));

        depth.clear();
        depth.resize(n, 0);
        dis.clear();
        dis.resize(n, 0);

        for (int i = 0; i < n - 1; ++i) {
            int u = edges[i].u;
            int v = edges[i].v;
            graph[u].push_back(i);
            graph[v].push_back(i);
        }
        E = edges;

        int rt = 0;
        dfs(rt, -1, 0, 0);

        events.clear();
        events.resize(n);
        for (int i = 0; i < queries.size(); ++i) {
            int u = queries[i].u;
            int v = queries[i].v;

            int p = lca(u, v);

            events[u].push_back(i + 1);
            events[v].push_back(i + 1);
            events[p].push_back(-(i + 1));
        }

        Q = queries;

        res.clear();
        res.resize(queries.size(), 0);

        vector<long long> sums(n, 0);
        vector<int> cnts(n, 0);
        dfs2(rt, -1, sums, cnts);

        return res;
    }


private:
    vector<long long> res;
    vector<vector<int>> events;
    vector<Edge> E;
    vector<Query> Q;

    vector<vector<int>> graph;
    vector<vector<int>> pars;
    vector<int> depth;
    vector<long long> dis;

    void dfs(int u, int p, int d, long long ds) {
        depth[u] = d;
        dis[u] = ds;
        pars[u][0] = p;

        int h = pars[u].size();
        for (int i = 1; i < h; ++i) {
            if (pars[u][i - 1] >= 0) {
                pars[u][i] = pars[pars[u][i - 1]][i - 1];
            }
        }

        for (auto e : graph[u]) {
            int v = E[e].u == u ? E[e].v : E[e].u;
            if (v == p) {
                continue;
            }
            dfs(v, u, d + 1, ds + E[e].w);
        }
    }

    int lca(int u, int v) {
        if (u == -1 || v == -1) {
            return u == -1 ? v : u;
        }
        if (u == v) {
            return u;
        }
        if (depth[u] > depth[v]) {
            swap(u, v);
        }
        int h = pars[u].size();
        for (int i = h - 1; i >= 0; --i) {
            int p = pars[v][i];
            if (p == -1) {
                continue;
            }
            if (depth[p] >= depth[u]) {
                v = p;
            }
        }
        if (v == u) {
            return u;
        }
        for (int i = h - 1; i >= 0; --i) {
            if (pars[u][i] != pars[v][i]) {
                u = pars[u][i];
                v = pars[v][i];
            }
        }

        return pars[u][0];
    }

    void dfs2(int u, int p, vector<long long>& sums, vector<int>& cnts) {
        
        for (auto ev : events[u]) {
            int sign = ev < 0 ? -1 : 1;
            int id = abs(ev) - 1;

            int clr = Q[id].x;
            long long nw = Q[id].y;
            long long d = dis[u];
            d -= sums[clr];
            d += cnts[clr] * nw; 
            
            if (sign < 0) {
                res[id] -= 2 * d;
            } else {
                res[id] += d;
            }
        }

        for (auto e : graph[u]) {
            int v = E[e].u == u ? E[e].v : E[e].u;
            if (v == p) {
                continue;
            }

            int clr = E[e].c;
            int w = E[e].w;
            sums[clr] += w;
            cnts[clr] += 1;

            dfs2(v, u, sums, cnts);

            sums[clr] -= w;
            cnts[clr] -= 1;
        }

    }
};

int main(int argc, char** argv) {
    ios::sync_with_stdio(false);
    cin.tie(0);

    int n, q;
    cin >> n >> q;
    vector<Edge> edges;
    for (int i = 0; i < n - 1; ++i) {
        int u, v, c, d;
        cin >> u >> v >> c >> d;
        --u, --v, --c;
        edges.emplace_back(u, v, c, d);
    }

    vector<Query> queries;
    for (int i = 0; i < q; ++i) {
        int x, y, u, v;
        cin >> x >> y >> u >> v;
        --x, --u, --v;
        queries.emplace_back(i, x, y, u, v);
    }

    Solution sol;
    auto res = sol.solve(n, edges, queries);
    
    for (int i = 0; i < q; ++i) {
        cout << res[i] << "\n";
    }

    return 0;
}