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 <bits/stdc++.h>
using namespace std;

// 0-indexed
template <class T>
struct BIT {
  int treesize;
  vector<T> lst;
  // constructor
  BIT(int newn = 0) : treesize(newn), lst(newn + 1, 0) {}
  // a_place += num
  void add(int place, T num) {
    ++place;
    while (place <= treesize) {
      lst[place] += num;
      place += place & -place;
    }
  }
  // sum between [0,place)
  T sum(int place) {
    T res = 0;
    while (place > 0) {
      res += lst[place];
      place -= place & -place;
    }
    return res;
  }
  // sum [l,r)
  T sum(int left, int right) { return sum(right) - sum(left); }
};

struct LowestCommonAncestor {
  int n, root, h;
  vector<vector<int>> g, par;
  vector<int> dep;
  LowestCommonAncestor(int _n = 1, int r = 0) : n(n), root(r), g(n), dep(n) {
    h = 1;
    while ((1 << h) <= n) ++h;
    par.assign(h, vector<int>(n, -1));
  }
  LowestCommonAncestor(const vector<vector<int>> &_g, const int r = 0)
      : n(_g.size()), root(r), g(_g), dep(_g.size()) {
    h = 1;
    while ((1 << h) <= n) ++h;
    par.assign(h, vector<int>(n, -1));
    build();
  }
  void add(int a, int b) {
    g[a].push_back(b);
    g[b].push_back(a);
  }
  void dfs(int now, int bf, int d) {
    par[0][now] = bf;
    dep[now] = d;
    for (int &to : g[now])
      if (to != bf) dfs(to, now, d + 1);
  }
  void build() {
    dfs(root, -1, 0);
    for (int i = 0; i + 1 < h; ++i)
      for (int j = 0; j < n; ++j) {
        if (par[i][j] < 0)
          par[i + 1][j] = -1;
        else
          par[i + 1][j] = par[i][par[i][j]];
      }
  }
  int calc(int x, int y) {
    if (dep[x] > dep[y]) swap(x, y);
    for (int i = 0; i < h; ++i)
      if ((dep[y] - dep[x]) >> i & 1) y = par[i][y];
    if (x == y) return x;
    for (int i = h - 1; i >= 0; --i)
      if (par[i][x] != par[i][y]) {
        x = par[i][x];
        y = par[i][y];
      }
    return par[0][y];
  }
};

struct HeavyLightDecomposition {
  int root;
  vector<vector<int>> g;
  vector<int> sz, par, in, out, head;
  HeavyLightDecomposition(int n = 1, int _root = 0)
      : root(_root), g(n), sz(n), par(n), in(n), out(n), head(n) {}
  HeavyLightDecomposition(const vector<vector<int>> &_g, const int _root = 0)
      : root(_root),
        g(_g),
        sz(_g.size()),
        par(_g.size()),
        in(_g.size()),
        out(_g.size()),
        head(_g.size()) {
    build();
  }
  void add(int a, int b) {
    g[a].push_back(b);
    g[b].push_back(a);
  }
  void build() {
    dfs_sz(root, -1);
    int t = 0;
    dfs_hld(root, -1, t);
  }
  void dfs_sz(int now, int bf) {
    par[now] = bf;
    sz[now] = 1;
    if (g[now].size() && g[now][0] == bf) swap(g[now][0], g[now].back());
    for (auto &to : g[now]) {
      if (to == bf) continue;
      dfs_sz(to, now);
      sz[now] += sz[to];
      if (sz[g[now][0]] < sz[to]) swap(g[now][0], to);
    }
  }
  void dfs_hld(int now, int bf, int &t) {
    in[now] = t++;
    for (auto &to : g[now]) {
      if (to == bf) continue;
      head[to] = (g[now][0] == to ? head[now] : to);
      dfs_hld(to, now, t);
    }
    out[now] = t;
  }
  int lca(int x, int y) {
    for (;; y = par[head[y]]) {
      if (in[x] > in[y]) swap(x, y);
      if (head[x] == head[y]) return x;
    }
  }
  int chil(int x, int y) { return par[x] == y ? x : y; }
};

struct edge {
  int x, y, col;
  long long dis;
};

struct query {
  int id, x, y;
  long long d;
};

int n, q;

vector<vector<query>> queries;
vector<vector<int>> g, coledges;
vector<edge> edges;
vector<long long> res;
LowestCommonAncestor lca;
HeavyLightDecomposition et;
BIT<long long> cnt, sum;

void solve();

int main() {
  cin >> n >> q;
  queries.resize(n);
  g.resize(n);
  coledges.resize(n);
  edges.resize(n - 1);
  res.resize(q);
  for (int i = 0; i < n - 1; ++i) {
    cin >> edges[i].x >> edges[i].y >> edges[i].col >> edges[i].dis;
    --edges[i].x, --edges[i].y, --edges[i].col;
    g[edges[i].x].push_back(edges[i].y);
    g[edges[i].y].push_back(edges[i].x);
    coledges[edges[i].col].push_back(i);
  }
  lca = LowestCommonAncestor(g);
  et = HeavyLightDecomposition(g);
  cnt = BIT<long long>(2 * n);
  sum = BIT<long long>(2 * n);
  for (int i = 0; i < q; ++i) {
    int x, y, u, v;
    cin >> x >> y >> u >> v;
    queries[x - 1].push_back({i, --u, --v, y});
  }
  solve();
  for (int i = 0; i < q; ++i) cout << res[i] << endl;
  return 0;
}

void solve() {
  // make sum
  for (auto e : edges) {
    int chil = et.chil(e.x, e.y);
    sum.add(et.in[chil], e.dis);
    sum.add(et.out[chil], -e.dis);
  }
  for (int i = 0; i < n; ++i) {
    // remove col i edge
    for (int id : coledges[i]) {
      edge &e = edges[id];
      int chil = et.chil(e.x, e.y);
      cnt.add(et.in[chil], 1);
      cnt.add(et.out[chil], -1);
      sum.add(et.in[chil], -e.dis);
      sum.add(et.out[chil], e.dis);
    }
    // calc distance
    for (auto qu : queries[i]) {
      int r = lca.calc(qu.x, qu.y);
      long long now = sum.sum(et.in[r] + 1, et.in[qu.x] + 1) +
                      sum.sum(et.in[r] + 1, et.in[qu.y] + 1);
      now += qu.d * (cnt.sum(et.in[r] + 1, et.in[qu.x] + 1) +
                     cnt.sum(et.in[r] + 1, et.in[qu.y] + 1));
      res[qu.id] = now;
    }
    // add col i edge
    for (int id : coledges[i]) {
      edge &e = edges[id];
      int chil = et.chil(e.x, e.y);
      cnt.add(et.in[chil], -1);
      cnt.add(et.out[chil], 1);
      sum.add(et.in[chil], e.dis);
      sum.add(et.out[chil], -e.dis);
    }
  }
}