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: Wrong Answer)

#include <bits/stdc++.h>

using namespace std;

struct Edge {
    int u, v, c;
    long long d;
    Edge() {}
    Edge(int u, int v, int c, long long d): u(u), v(v), c(c), d(d) {}
    friend istream& operator>>(istream& in, Edge& e) {
        in >> e.u >> e.v >> e.c >> e.d;
        --e.u;
        --e.v;
        return in;
    }
    Edge opposite() const {
        return Edge(v, u, c, d);
    }
};

struct Shortcut {
    int node;
    map<int, int> num;
    map<int, long long> dist;
    long long total_dist;
};

Shortcut merge_shortcuts(Shortcut& s0, Shortcut s1) {
    for (auto entry : s0.num) {
        s1.num[entry.first] += entry.second;
    }
    for (auto entry : s0.dist) {
        s1.dist[entry.first] += entry.second;
    }
    s1.total_dist += s0.total_dist;
    return s1;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    long long prime = 1000000007;
    int n, q;
    cin >> n >> q;
    vector<vector<Edge>> adj_list(n);
    for (int i = 0; i < n-1; ++i) {
        Edge edge;
        cin >> edge;
        adj_list[edge.u].push_back(edge);
        adj_list[edge.v].push_back(edge.opposite());
    }
    vector<int> depth(n);
    vector<Edge> parent_edge(n);
    function<void (int, int, int)> root_tree = [&](int i, int p, int d) {
        if (p == -1) {
            parent_edge[i] = Edge(i, i, 0, 0);
        } else {
            int parent_index = -1;
            for (int j = 0; j < (int) adj_list[i].size(); ++j) {
                if (adj_list[i][j].v == p) {
                    parent_index = j;
                }
            }
            assert(parent_index != -1);
            parent_edge[i] = adj_list[i][parent_index];
            adj_list[i].erase(adj_list[i].begin() + parent_index);
        }
        for (Edge& edge : adj_list[i]) {
            root_tree(edge.v, edge.u, d+1);
        }
    };
    root_tree(0, -1, 0);
    mt19937 rng(chrono::system_clock::now().time_since_epoch().count());
    long long best_price = n*n, best_k = 0;
    for (int t = 0; t < 20; ++t) {
        long long price = 0;
        int k = rng() % n;
        for (int d : depth) {
            price += (k+d) & (-(k+d));
        }
        if (price < best_price) {
            best_price = price;
            best_k = k;
        }
    }
    for (int& d : depth) {
        d += best_k;
    }
    vector<vector<int>> p_shortcut(n);
    vector<vector<Shortcut>> shortcuts(n);
    for (int i = 0; i < n; ++i) {
        Shortcut s;
        s.node = parent_edge[i].v;
        s.num[parent_edge[i].c] = 1;
        s.dist[parent_edge[i].c] = parent_edge[i].d;
        s.total_dist = parent_edge[i].d;
        shortcuts[i].push_back(s);
        p_shortcut[i].push_back(parent_edge[i].v);
    }
    for (int t = 1; t < 20; ++t) {
        for (int i = 0; i < n; ++i) {
            if (i == 0 || depth[i] % (1 << t) == 0) {
                Shortcut& s0 = shortcuts[i][t-1]; // 2^(t-1) up.
                Shortcut& s1 = shortcuts[s0.node][t-1]; //2^(t-1) up.
                shortcuts[i].push_back(merge_shortcuts(s0, s1));
            }
            p_shortcut[i].push_back(p_shortcut[p_shortcut[i][t-1]][t-1]);
        }
    }
    vector<int> lg(n+1, 0);
    for (int i = 2; i <= n; ++i) {
        lg[i] = lg[i/2] + 1;
    }
    auto lca = [&](int u, int v) {
        if (depth[u] > depth[v]) {
            swap(u, v);
        }
        // so depth[u] <= depth(v)
        while (depth[u] < depth[v]) {
            u = p_shortcut[u][lg[depth[v]-depth[u]]];
        }
        // now u and v have the same depth
        if (u == v) {
            return u;
        }
        for (int t = 19; t >= 0; --t) {
            int u2 = p_shortcut[u][t], v2 = p_shortcut[v][t];
            if (u2 != v2) {
                u = u2;
                v = v2;
            }
        }
        return p_shortcut[u][0];
    };
    function<long long(int, int, int)> dist_to_root = [&](int u, int x, int y) {
        int num = 0;
        long long color_dist = 0LL;
        long long total_dist = 0LL;
        while (u != 0) {
            Shortcut& s = shortcuts[u].back();
            if (s.num.find(x) != s.num.end()) {
                num += s.num[x];
                color_dist += s.dist[x];
            }
            total_dist += s.total_dist;
            u = s.node;
        }
        return (total_dist - color_dist) + num * y;
    };
    vector<long long> results(q);
    for (int i = 0; i < q; ++i) {
        int x, y, u, v;
        cin >> x >> y >> u >> v;
        --u;
        --v;
        int w = lca(u, v);
        results[i] = dist_to_root(u, x, y) + dist_to_root(v, x, y) - 2*dist_to_root(w, x, y);
    }
    for (auto result : results) {
        cout << result << "\n";
    }
    return 0;
}