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: Time Limit Exceeded)

#include <bits/stdc++.h>

using namespace std;

#define INF 100000000
#define YJ 1145141919
#define INF_INT_MAX 2147483647
#define INF_LL 9223372036854775
#define INF_LL_MAX 9223372036854775807
#define EPS 1e-10
#define MOD 1000000007
#define MOD9 998244353
#define Pi acos(-1)
#define LL long long
#define ULL unsigned long long
#define LD long double

#define int long long

using II = pair<int, int>;

int gcd(int a, int b) { return b != 0 ? gcd(b, a % b) : a; }
int lcm(int a, int b) { return a * b / gcd(a, b); }
int extgcd(int a, int b, int &x, int &y) { int g = a; x = 1; y = 0; if (b != 0) g = extgcd(b, a % b, y, x), y -= (a / b) * x; return g; }

#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define REP(i,n) FOR(i,0,n)
#define ALL(a)  begin((a)), end((a))
#define RALL(a) (a).rbegin(), (a).rend()
#define PB push_back
#define MP make_pair
#define SZ(a) int((a).size())

const int MAX_N = 100005;
const int MAX_SQRT = 50;
int N, Q;

struct Edge {
  Edge(int c = -1, int d = -1, int to = -1) : c(c), d(d), to(to) {}
  int c, d, to;
};

struct Node {
  Node() {}
  vector<Edge> nexts;
  Edge preEdge;
  int pre = -1;
  int depth = 0;
  int sqrtPre = -1;
};

Node nodes[MAX_N];
vector<Edge> edges[MAX_N];

void initNodes(int pos, int pre = -1, int d = 0)
{
  nodes[pos].pre = pre;
  nodes[pos].depth = d;
  for(const Edge& edge : edges[pos]) {
    if(edge.to == pre) continue;
    nodes[pos].nexts.push_back(edge.to);
    nodes[edge.to].preEdge = edge;
    nodes[edge.to].preEdge.to = pos;
    initNodes(edge.to, pos, d+1);
  }
}

map<int, int> DIST_COUNT[MAX_N];
map<int, int> DIST_COST[MAX_N];
int DIST_TOTAL[MAX_N];

signed main()
{
  cin >> N >> Q;
  REP(n,N-1) {
    int a, b, c, d; cin >> a >> b >> c >> d; a--; b--; c--;
    edges[a].push_back(Edge(c,d,b));
    edges[b].push_back(Edge(c,d,a));
  }

  initNodes(0);

  REP(n,N) {
    int totalCost = 0;
    bool flag = true;
    int pos = n;

    if(nodes[n].pre != -1 && DIST_TOTAL[nodes[n].pre] > 0) {
      DIST_COUNT[n] = DIST_COUNT[nodes[n].pre];
      DIST_COST[n] = DIST_COST[nodes[n].pre];
      DIST_TOTAL[n] = DIST_TOTAL[nodes[n].pre];

      {
        const Edge& preEdge = nodes[pos].preEdge;
        DIST_COUNT[n][preEdge.c]++;
        DIST_COST[n][preEdge.c] += preEdge.d;
        DIST_TOTAL[n] += preEdge.d;
      }

      for(int d = 0; d < MAX_SQRT-1; d++) {
        pos = nodes[pos].pre;
      }
      
      {
        const Edge& preEdge = nodes[pos].preEdge;
        DIST_COUNT[n][preEdge.c]--;
        DIST_COST[n][preEdge.c] -= preEdge.d;
        DIST_TOTAL[n] -= preEdge.d;

        if(DIST_COUNT[n][preEdge.c] == 0) {
          DIST_COUNT[n].erase(preEdge.c);
          DIST_COST[n].erase(preEdge.c);
        }
      }
      
      continue;
    }

    for(int d = 0; d < MAX_SQRT && flag; d++) {
      if(nodes[pos].pre == -1) {
        flag = false;
        break;
      }
      const Edge& preEdge = nodes[pos].preEdge;
      DIST_COUNT[n][preEdge.c]++;
      DIST_COST[n][preEdge.c] += preEdge.d;
      totalCost += preEdge.d;
      pos = nodes[pos].pre;
    }

    if(flag) {
      DIST_TOTAL[n] = totalCost;
      nodes[n].sqrtPre = pos;
    }
  }

  REP(q,Q) {
    int x, y, u, v; 
    cin >> x >> y >> u >> v;
    x--; u--; v--;
    if(nodes[v].depth < nodes[u].depth) { // vを上にあげる
      swap(u,v);
    }

    int ans = 0;

    // 深さを揃える
    while(abs(nodes[v].depth - nodes[u].depth) > MAX_SQRT) {
      if(DIST_TOTAL[v] > 0) {
        ans += DIST_TOTAL[v] - DIST_COST[v][x] + DIST_COUNT[v][x] * y;
      } else {
        ans += DIST_TOTAL[v];
      }
      v = nodes[v].sqrtPre;
    }

    while(nodes[v].depth != nodes[u].depth) {
      if(nodes[v].preEdge.c == x) {
        ans += y;
      } else {
        ans += nodes[v].preEdge.d;
      }
      v = nodes[v].pre;
    }

    while(nodes[u].sqrtPre != nodes[v].sqrtPre) {
      if(DIST_TOTAL[v] > 0) {
        ans += DIST_TOTAL[v] - DIST_COST[v][x] + DIST_COUNT[v][x] * y;
      } else {
        ans += DIST_TOTAL[v];
      }
      if(DIST_TOTAL[u] > 0) {
        ans += DIST_TOTAL[u] - DIST_COST[u][x] + DIST_COUNT[u][x] * y;
      } else {
        ans += DIST_TOTAL[u];
      }

      v = nodes[v].sqrtPre;
      u = nodes[u].sqrtPre;
    }

    while(u != v) {
      if(nodes[u].preEdge.c == x) {
        ans += y;
      } else {
        ans += nodes[u].preEdge.d;
      }

      if(nodes[v].preEdge.c == x) {
        ans += y;
      } else {
        ans += nodes[v].preEdge.d;
      }

      u = nodes[u].pre;
      v = nodes[v].pre;
    }

    cout << ans << endl;
  }

  return 0;
}