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>

template <typename InputIterator>
typename InputIterator::value_type summation(InputIterator first,
                                             InputIterator last) {
  return std::accumulate(first, last, typename InputIterator::value_type());
}
template <typename T>
std::istream &operator>>(std::istream &stream, std::vector<T> &v);
template <typename T1, typename T2>
std::istream &operator>>(std::istream &stream, std::pair<T1, T2> &p);
template <typename T>
std::istream &operator>>(std::istream &stream, std::vector<T> &v) {
  for (auto &i : v) {
    stream >> i;
  }
  return stream;
}
template <typename T1, typename T2>
std::istream &operator>>(std::istream &stream, std::pair<T1, T2> &p) {
  stream >> p.first >> p.second;
  return stream;
}

int main() {
  int64_t n, q;
  std::cin >> n >> q;

  struct edge {
    int64_t node;
    int64_t color;
    int64_t length;

    edge(int64_t node, int64_t color, int64_t length)
        : node(node), color(color), length(length) {}
  };

  std::vector<std::vector<edge>> node(n);

  for (int64_t i = 0; i < n - 1; i++) {
    int64_t a, b, c, d;
    std::cin >> a >> b >> c >> d;
    a--;
    b--;
    c--;
    node[a].emplace_back(b, c, d);
    node[b].emplace_back(a, c, d);
  }
  const int64_t logn = std::round(std::log2(n));

  std::vector<std::vector<int64_t>> par(n, std::vector<int64_t>(logn + 2));

  std::fill(par[0].begin(), par[0].end(), 0);

  std::vector<int64_t> depth(n);
  std::vector<int64_t> distance(n);
  depth[0] = 0;
  distance[0] = 0;

  std::deque<int64_t> queue;
  std::vector<bool> flag(n, false);
  queue.push_back(0);

  while (!queue.empty()) {
    flag[queue.front()] = true;
    for (const auto &i : node[queue.front()]) {
      if (flag[i.node] == false) {
        queue.push_back(i.node);
        par[i.node][1] = queue.front();
        depth[i.node] = depth[queue.front()] + 1;
        distance[i.node] = distance[queue.front()] + i.length;
      }
    }
    queue.pop_front();
  }
  for (int64_t i = 0; i < n; i++) {
    par[i][0] = i;
  }
  for (int64_t i = 2; i <= logn; i++) {
    for (int64_t j = 0; j < n; j++) {
      par[j][i] = par[par[j][i - 1]][i - 1];
    }
  }

  const auto parent = [&](const int64_t n, const int64_t i) {
    int64_t ans = n;
    for (int64_t j = logn; 1 <= j; j--) {
      if (((1 << (j - 1)) & i) != 0) {
        ans = par[ans][j];
      }
    }
    return ans;
  };
  const auto lca = [&](int64_t a, int64_t b) {
    if (depth[a] < depth[b]) {
      b = parent(b, depth[b] - depth[a]);
    } else {
      a = parent(a, depth[a] - depth[b]);
    }

    if (a == b) {
      return a;
    }

    for (int64_t j = logn; 0 <= j; j--) {
      if (par[a][j] != par[b][j]) {
        a = par[a][j];
        b = par[b][j];
      }
    }
    return par[a][1];
  };

  return 0;

  std::fill(flag.begin(), flag.end(), false);
  std::vector<std::vector<std::pair<int64_t, int64_t>>> color(
      n, std::vector<std::pair<int64_t, int64_t>>());
  std::vector<std::vector<std::pair<int64_t, int64_t>>> color_sum(
      n, std::vector<std::pair<int64_t, int64_t>>());
  std::vector<int64_t> node_index(n);
  node_index[0] = 0;

  std::deque<std::tuple<int64_t, int64_t, int64_t, int64_t>> queue2;
  for (const auto &i : node[0]) {
    queue2.emplace_front(i.node, 0, i.color, i.length);
    queue2.emplace_front(0, i.node, i.color, i.length);
  }
  flag[0] = false;

  int64_t index = 0;
  while (!queue2.empty()) {
    const auto edge = queue2.front();
    queue2.pop_front();
    const auto node_before = std::get<0>(edge);
    const auto node_next = std::get<1>(edge);
    const auto color_edge = std::get<2>(edge);
    const auto length = std::get<3>(edge);

    if (flag[node_next] == false) {
      flag[node_next] = true;
      node_index[node_next] = index + 1;
    }
    if (depth[node_before] < depth[node_next]) {
      if (color_sum[color_edge].empty()) {
        color[color_edge].emplace_back(index, 1);
        color_sum[color_edge].emplace_back(index, length);
      } else {
        color[color_edge].emplace_back(index,
                                       color[color_edge].back().second + 1);
        color_sum[color_edge].emplace_back(
            index, color_sum[color_edge].back().second + length);
      }
    } else {
      if (color_sum[color_edge].empty()) {
        color[color_edge].emplace_back(index, -1);
        color_sum[color_edge].emplace_back(index, -length);
      } else {
        color[color_edge].emplace_back(index,
                                       color[color_edge].back().second - 1);
        color_sum[color_edge].emplace_back(
            index, color_sum[color_edge].back().second - length);
      }
    }

    for (const auto &i : node[node_next]) {
      if (flag[i.node] == false) {
        queue2.emplace_front(i.node, node_next, i.color, i.length);
        queue2.emplace_front(node_next, i.node, i.color, i.length);
      }
    }
    index++;
  }

  const auto dist = [&](const auto node, const auto col,
                        const auto change) -> int64_t {
    const auto end = node_index[node];
    const auto def = distance[node];
    if (color[col].empty()) {
      return def;
    }
    if (color[col].back().first < end) {
      return def + color[col].back().second * change -
             color_sum[col].back().second;
    }
    if (end <= color[col].front().first) {
      return def;
    }

    auto right = color[col].size() - 1;
    int64_t left = 0;

    while (left < right) {
      const auto next = (left + right) / 2;
      if (left == next) {
        break;
      }
      if (end <= color[col][next].first) {
        right = next;
      } else {
        left = next;
      }
    }
    return def + color[col][left].second * change - color_sum[col][left].second;
  };

  for (int64_t i = 0; i < q; i++) {
    int64_t x, y, u, v;
    std::cin >> x >> y >> u >> v;
    x--;
    u--;
    v--;
    const auto l = lca(u, v);
    std::cout << dist(u, x, y) + dist(v, x, y) + dist(l, x, y) << std::endl;
  }

  return 0;
}