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 <cstdio>
#include <algorithm>
#include <cmath>
#include <vector>
#include <iostream>
using namespace std;

#define st first
#define nd second

const int N = (int) 1e5 + 5;
const int LOGN = (int) log2(N) + 3;
const int INF = (int) 2e9 + 9;

struct TEdge {
	int v, c, w;
	TEdge() {}
	TEdge(int v, int c, int w) : v(v), c(c), w(w) {}
};

struct TNode {
	int in, ou, c, w;
	TNode() {}
	TNode(int in, int ou, int c, int w) : in(in), ou(ou), c(c), w(w) {}
	bool operator < (const TNode &op) const {
		return in == op.in ? ou < op.ou : in < op.in;
	}
} node[N];

struct TQuery {
	int c, w, u, v;
	TQuery() {}
	TQuery(int c, int w, int u, int v) : c(c), w(w), u(u), v(v) {}
} query[N];

int n, q;
vector <TEdge> g[N];

int vtime;
int in[N], ou[N];
TEdge edgeNode[N];

int logn;
int depth[N], dad[N][LOGN], dist[N];

int pos;
int cntQuery[N], sumQuery[N];

vector <int> color;
bool markColor[N];
vector <int> colOut[N];

struct TData {
	int u, c, idx, minus;
	TData() {}
	TData(int u, int c, int idx, int minus) : u(u), c(c), idx(idx), minus(minus) {}
	bool operator < (const TData &op) const {
		return in[u] < in[op.u];
	}
};

vector <TData> ver;

void dfsEulerTour(int u, int p) {
	in[u] = ++vtime; 
	for (int i = 0; i < g[u].size(); i++) {
		int v = g[u][i].v, w = g[u][i].w;
		if (v == dad[u][0]) continue;
		edgeNode[v] = g[u][i];
		depth[v] = depth[u] + 1;
		dist[v] = dist[u] + w;
		dfsEulerTour(v, dad[v][0] = u);
	}
	ou[u] = ++vtime;
}

void buildLca() {
	for (int k = 1; k <= logn; k++)
		for (int i = 1; i <= n; i++) dad[i][k] = dad[dad[i][k - 1]][k - 1];
}

int findLca(int u, int v) {
	for (int k = logn; k >= 0; k--)
		if (depth[dad[u][k]] >= depth[v]) u = dad[u][k];
	for (int k = logn; k >= 0; k--)
		if (depth[dad[v][k]] >= depth[u]) v = dad[v][k];
	if (u == v) return u;
	for (int k = logn; k >= 0; k--)
		if (dad[u][k] != dad[v][k]) {
			u = dad[u][k];
			v = dad[v][k];
		}
	return dad[u][0];
}

void compress() {
	vector <int> zip; zip.push_back(0);
	for (int i = 1; i <= n; i++) zip.push_back(ou[i]);
	sort(zip.begin(), zip.end());
	for (int i = 1; i <= n; i++) ou[i] = lower_bound(zip.begin(), zip.end(), ou[i]) - zip.begin(); 
}

void init() {
	logn = log2(n) + 1;
	depth[1] = 1;
	dfsEulerTour(1, 0);
	buildLca();
	compress();
	for (int i = 1; i <= n; i++) node[i] = TNode(in[i], ou[i], edgeNode[i].c, edgeNode[i].w);
	pos = 1;
	sort(node + 1, node + 1 + n);
}

vector <pair <int, int> > fw[3 * N];

void upd(int c, int i, int w) {
	for (; i < fw[c].size(); i += i & -i) {
		fw[c][i].st++;
		fw[c][i].nd += w;
	}
}

pair <int, int> get(int c, int i) {
	pair <int, int> res = make_pair(0, 0);
	for (; i > 0; i -= i & -i) {
		res.st += fw[c][i].st;
		res.nd += fw[c][i].nd;
	}
	return res;
}

int main() {
	// freopen("in.inp", "r", stdin); 
	// freopen(".ou", "w", stdou);
	scanf("%d %d", &n, &q);
	for (int i = 1; i < n; i++) {
		int u, v, c, w; scanf("%d %d %d %d", &u, &v, &c, &w);
		g[u].push_back(TEdge(v, c, w));
		g[v].push_back(TEdge(u, c, w));
	}
	init();
	for (int i = 1; i <= q; i++) {
		int c, w, u, v; scanf("%d %d %d %d", &c, &w, &u, &v);
		int p = findLca(u, v);
		query[i] = TQuery(c, w, u, v);
		ver.push_back(TData(u, c, i, 1));
		ver.push_back(TData(v, c, i, 1));
		ver.push_back(TData(p, c, i, -1));
		if (markColor[c] == false) {
			color.push_back(c);
			markColor[c] = true;
		}
	}
	for (int i = 1; i <= n; i++) {
		int c = edgeNode[i].c;
		colOut[c].push_back(ou[i]);
	}
	for (int iCol = 0; iCol < color.size(); iCol++) {
		int c = color[iCol];
		sort(colOut[c].begin(), colOut[c].end());
		fw[c].resize(colOut[c].size() + 2);
	}
	sort(ver.begin(), ver.end());
	for (int i = 0; i < ver.size(); i++) {
		int u = ver[i].u, c = ver[i].c, idx = ver[i].idx, minus = ver[i].minus;
		while (pos <= n && node[pos].in <= in[u]) {
			int position = lower_bound(colOut[c].begin(), colOut[c].end(), node[pos].ou) - colOut[c].begin() + 1;
			if (position != colOut[c].size() + 1) upd(node[pos].c, position, node[pos].w);
			pos++;
		}
		pair <int, int> resRight = get(c, fw[c].size() - 1);
		int position = lower_bound(colOut[c].begin(), colOut[c].end(), ou[u]) - colOut[c].begin() + 1;
		pair <int, int> resLeft  = get(c, position);
		cntQuery[idx] += minus * (resRight.st - resLeft.st);
		sumQuery[idx] += minus * (resRight.nd - resLeft.nd);
		if (edgeNode[u].c == c) {
			cntQuery[idx]++;
			sumQuery[idx] += edgeNode[u].w;
		}
	}
	for (int i = 1; i <= q; i++) {
		int u = query[i].u, v = query[i].v, p = findLca(u, v), w = query[i].w;
		int ans = dist[u] + dist[v] - 2 * dist[p];
		//cout << ans << " ";
		ans -= sumQuery[i];
		ans += cntQuery[i] * w;
		//cout << cntQuery[i] << " " << sumQuery[i] << " "; 
		printf("%d\n", ans);
	}
	return 0;
}

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