Language: C++

#include <algorithm>
#include <iostream>
#include <limits>
#include <unordered_map>
#include <unordered_set>
#include <vector>

using ::std::cin;
using ::std::cout;
using ::std::endl;
using ::std::string;
using ::std::vector;

using int64 = long long;

struct Edge {
  int from;
  int to;
  int color;
  int64 weight;
};

struct Query {
  int color;
  int64 weight;
  int from;
  int to;
};

vector<vector<Edge>> ReadUndirectedGraph(
    int n, int m, bool is_one_indexed=false) {
  vector<vector<Edge>> graph(n);
  for (int i = 0; i < m; i++) {
    int v1, v2;
    int color;
    int64 weight;
    cin >> v1 >> v2 >> color >> weight;
    if (is_one_indexed) {
      v1--;
      v2--;
    }
    graph[v1].push_back(Edge({v1, v2, color, weight}));
    graph[v2].push_back(Edge({v2, v1, color, weight}));
  }
  return graph;
}

class LCASolver {
  static constexpr int MAX_LOG_V = 18;
  vector<int> depths;
  vector<vector<int>> parentMatrix;
 public:
  LCASolver(const vector<vector<Edge>>& graph) {
    int n = graph.size();
    depths = vector<int>(n);
    parentMatrix = vector<vector<int>>(MAX_LOG_V, vector<int>(n));
    std::function<void(int, int, int)> dfs = [&](int v, int parent, int depth) {
      parentMatrix[0][v] = parent;
      depths[v] = depth;
      for (const auto& e : graph[v]) {
        if (e.to == parent) continue;
        dfs(e.to, v, depth + 1);
      }
    };
    dfs(0, -1, 0);

    for (int k = 0; k < MAX_LOG_V - 1; k++) {
      for (int v = 0; v < n; v++) {
        if (parentMatrix[k][v] < 0) parentMatrix[k + 1][v] = -1;
        else parentMatrix[k + 1][v] = parentMatrix[k][parentMatrix[k][v]];
      }
    }
  }

  int ComputeLCA(int v1, int v2) {
    if (depths[v1] > depths[v2]) return ComputeLCA(v2, v1);
    for (int k = 0; k < MAX_LOG_V; k++) {
      if (((depths[v2] - depths[v1]) >> k) & 1) {
        v2 = parentMatrix[k][v2];
      }
    }
    if (v1 == v2) return v1;

    for (int k = MAX_LOG_V - 1; k >= 0; k--) {
      if (parentMatrix[k][v1] != parentMatrix[k][v2]) {
        v1 = parentMatrix[k][v1];
        v2 = parentMatrix[k][v2];
      }
    }
    return parentMatrix[0][v1];
  }
};

int main() {
  int n, numQueries;
  cin >> n >> numQueries;
  vector<vector<Edge>> graph = ReadUndirectedGraph(n, n - 1, true);
  vector<Query> queries;
  for (int i = 0; i < numQueries; i++) {
    int color;
    int64 weight;
    int v1, v2;
    cin >> color >> weight >> v1 >> v2;
    v1--;
    v2--;
    queries.push_back(Query({color, weight, v1, v2}));
  }

  LCASolver lca_solver(graph);

  vector<std::unordered_set<int>> vertexToQueryColorSet(n);
  for (const auto& query : queries) {
    vertexToQueryColorSet[query.from].insert(query.color);
    vertexToQueryColorSet[query.to].insert(query.color);
    int lca = lca_solver.ComputeLCA(query.from, query.to);
    vertexToQueryColorSet[lca].insert(query.color);
  }
 
  vector<int64> distances(n);
  vector<int> colorToCount(n);
  vector<int64> colorToWeight(n);
  vector<std::unordered_map<int, int>> vertexToColorCountMap(n);
  vector<std::unordered_map<int, int64>> vertexToColorWeightMap(n);
  std::function<void(int, int, int64)> dfs =
      [&](int v, int parent, int64 distance) {
    for (int c : vertexToQueryColorSet[v]) {
      vertexToColorCountMap[v][c] = colorToCount[c];
      vertexToColorWeightMap[v][c] = colorToWeight[c];
    }

    distances[v] = distance;

    for (const auto& e : graph[v]) {
      if (e.to == parent) continue;
      colorToCount[e.color]++;
      colorToWeight[e.color] += e.weight;
      dfs(e.to, v, distance + e.weight);
      colorToCount[e.color]--;
      colorToWeight[e.color] -= e.weight;
    }
  };
  dfs(0, -1, 0);

  for (const auto& query : queries) {
    int lca = lca_solver.ComputeLCA(query.from, query.to);
    int64 ans = distances[query.from] + distances[query.to]
        - 2 * distances[lca];
    ans += vertexToColorCountMap[query.from][query.color] * query.weight
        - vertexToColorWeightMap[query.from][query.color];
    ans += vertexToColorCountMap[query.to][query.color] * query.weight
        - vertexToColorWeightMap[query.to][query.color];
    ans -= 2 * (vertexToColorCountMap[lca][query.color] * query.weight
        - vertexToColorWeightMap[lca][query.color]);
    cout << ans << "\n";
  }
  return 0;
}

Compiler output:
a.cc: In constructor 'LCASolver::LCASolver(const std::vector<std::vector<Edge> >&)':
a.cc:57:10: error: 'function' is not a member of 'std'
   57 |     std::function<void(int, int, int)> dfs = [&](int v, int parent, int depth) {
      |          ^~~~~~~~
a.cc:7:1: note: 'std::function' is defined in header '<functional>'; this is probably fixable by adding '#include <functional>'
    6 | #include <vector>
  +++ |+#include <functional>
    7 | 
a.cc:57:37: error: expression list treated as compound expression in functional cast [-fpermissive]
   57 |     std::function<void(int, int, int)> dfs = [&](int v, int parent, int depth) {
      |                                     ^
a.cc:57:19: error: expected primary-expression before 'void'
   57 |     std::function<void(int, int, int)> dfs = [&](int v, int parent, int depth) {
      |                   ^~~~
a.cc:65:5: error: 'dfs' was not declared in this scope
   65 |     dfs(0, -1, 0);
      |     ^~~
a.cc: In function 'int main()':
a.cc:124:8: error: 'function' is not a member of 'std'
  124 |   std::function<void(int, int, int64)> dfs =
      |        ^~~~~~~~
a.cc:124:8: note: 'std::function' is defined in header '<functional>'; this is probably fixable by adding '#include <functional>'
a.cc:124:37: error: expression list treated as compound expression in functional cast [-fpermissive]
  124 |   std::function<void(int, int, int64)> dfs =
      |                                     ^
a.cc:124:17: error: expected primary-expression before 'void'
  124 |   std::function<void(int, int, int64)> dfs =
      |                 ^~~~
a.cc:142:3: error: 'dfs' was not declared in this scope
  142 |   dfs(0, -1, 0);
      |   ^~~