# HackerRank Recalling Early Days GP with Trees problem solution

In this HackerRank Recalling Early Days GP with Trees problem solution, You are given a tree with N nodes and each has a value associated with it. You are given Q queries, each of which is either an update or a retrieval operation. You need to return the sum of the node values (S) lying in the path from node i to node j modulo 100711433.

## Problem solution in Java Programming.

import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Deque;
import java.util.List;
import java.util.StringTokenizer;

public class Solution2 {

static final int LOGN = 17;
static final int MOD = 100_711_433;

static long power(long a, int n) {
long r = 1;
for (; n > 0; n >>= 1, a = a*a%MOD) {
if ((n & 1) > 0) {
r = r*a%MOD;
}
}
return r;
}

static long add(long x, long y) {
return (x+y)%MOD;
}

static int inv(int x) {
long r = 1;
for (; x > 1; x = MOD%x) {
r = MOD/x * -r % MOD;
}
return (int) r;
}

static int[] dep;
static int[][] par;
static List<Integer>[] e;

static class Node {
int d;
int v;
int p;
Node(int d, int v, int p) {
this.d = d;
this.v = v;
this.p = p;
}
}

static void dfs(int d, int v, int p) {
while (!queue.isEmpty()) {
Node node = queue.poll();
dep[node.v] = node.d;
par[0][node.v] = node.p;
for (int u: e[node.v]) {
if (u != node.p) {
}
}
}
}

static int r;
static int invr;
static long[] d;
static long[] dd;

static class Node2 {
int v;
int p;
boolean start = true;
Node2(int v, int p) {
this.v = v;
this.p = p;
}
}

static void dfs2(int v, int p) {
while (!queue.isEmpty()) {
Node2 node = queue.peek();
if (node.start) {
for (int u: e[node.v]) {
if (u != node.p) {
queue.push(new Node2(u, node.v));
}
}
node.start = false;
} else {
if (node.p >= 0) {
d[node.p] = add(d[node.p], d[node.v] * r);
dd[node.p] = add(dd[node.p], dd[node.v] * invr);
}
queue.remove();
}
}
}

static long[] path;

static class Node3 {
int v;
int p;
long s;
Node3(int v, int p, long s) {
this.v = v;
this.p = p;
this.s = s;
}
}

static void dfs3(int v, int p, long s) {
while (!queue.isEmpty()) {
Node3 node = queue.poll();
path[node.v] = (node.s+d[node.v]+dd[node.v])%MOD;
for (int u: e[node.v]) {
if (u != node.p) {
queue.push(new Node3(u, node.v, (node.s+d[node.v]+dd[node.v])%MOD));
}
}
}
}

static int lca(int v, int u) {
if (dep[v] < dep[u]) {
int temp = v;
v = u;
u = temp;
}
for (int i = LOGN; --i >= 0; ) {
if (1 << i <= dep[v]-dep[u]) {
v = par[i][v];
}
}
if (v == u) {
return v;
}
for (int i = LOGN; --i >= 0; ) {
if (par[i][v] != par[i][u]) {
v = par[i][v];
u = par[i][u];
}
}
return par[0][v];
}

public static void main(String[] args) throws IOException {
BufferedWriter bw = new BufferedWriter(new FileWriter(System.getenv("OUTPUT_PATH")));

int n = Integer.parseInt(st.nextToken());
r = Integer.parseInt(st.nextToken()) % MOD;
invr = r > 0 ? inv(r) : 0;
e = new List[n];
for (int i = 0; i < n; i++) {
}
for (int i = 0; i < n-1; i++) {
int u = Integer.parseInt(st.nextToken())-1;
int v = Integer.parseInt(st.nextToken())-1;
}
dep = new int[n];
par = new int[LOGN][n];
dfs(0, 0, -1);
for (int j = 1; j < LOGN; j++) {
for (int i = 0; i < n; i++) {
par[j][i] = par[j-1][i] < 0 ? -1 : par[j-1][par[j-1][i]];
}
}
int upd = Integer.parseInt(st.nextToken());
int q = Integer.parseInt(st.nextToken());
d = new long[n];
dd = new long[n];
for (int i=0; i < upd; i++) {
int v = Integer.parseInt(st.nextToken()) - 1;
int u = Integer.parseInt(st.nextToken()) - 1;
int w = lca(v, u);
int x = Integer.parseInt(st.nextToken());

if (r > 0) {
long xl = power(r, dep[v]-dep[w]), xr = power(r, dep[u]-dep[w]);
if (w > 0) {
d[par[0][w]] = add(d[par[0][w]], - (x * xl % MOD * r));
}
dd[u] = add(dd[u], x * xl % MOD * xr);
dd[w] = add(dd[w], - x * xl);
} else {
}
}
dfs2(0, -1);
path = new long[n];
dfs3(0, -1, 0);
for (int i=0; i < q; i++) {
int v = Integer.parseInt(st.nextToken()) - 1;
int u = Integer.parseInt(st.nextToken()) - 1;
int w = lca(v, u);
long result = ((path[v]+path[u]-path[w]-(w > 0 ? path[par[0][w]] : 0)) % MOD + MOD) % MOD;
bw.write(String.valueOf(result) + "\n");
}

bw.newLine();
bw.close();
br.close();
}
}

## Problem solution in C++ programming.

#define _CRT_SECURE_NO_WARNINGS
#include <string>
#include <vector>
#include <algorithm>
#include <numeric>
#include <set>
#include <map>
#include <queue>
#include <iostream>
#include <sstream>
#include <cstdio>
#include <cmath>
#include <ctime>
#include <cstring>
#include <cctype>
#include <list>
#include <cassert>
#define rep(i,n) for(int (i)=0;(i)<(int)(n);++(i))
#define rer(i,l,u) for(int (i)=(int)(l);(i)<=(int)(u);++(i))
#define reu(i,l,u) for(int (i)=(int)(l);(i)<(int)(u);++(i))
#if defined(_MSC_VER) || __cplusplus > 199711L
#define aut(r,v) auto r = (v)
#else
#define aut(r,v) typeof(v) r = (v)
#endif
#define each(it,o) for(aut(it, (o).begin()); it != (o).end(); ++ it)
#define all(o) (o).begin(), (o).end()
#define pb(x) push_back(x)
#define mp(x,y) make_pair((x),(y))
#define mset(m,v) memset(m,v,sizeof(m))
#define INF 0x3f3f3f3f
#define INFL 0x3f3f3f3f3f3f3f3fLL
#define EPS 1e-9
using namespace std;
typedef vector<int> vi; typedef pair<int,int> pii; typedef vector<pair<int,int> > vpii;
typedef long long ll; typedef vector<long long> vl; typedef pair<long long,long long> pll; typedef vector<pair<long long,long long> > vpll;
typedef vector<string> vs; typedef long double ld;
template<typename T, typename U> inline void amin(T &x, U y) { if(x > y) x = y; }
template<typename T, typename U> inline void amax(T &x, U y) { if(x < y) x = y; }

struct CentroidPathDecomposition {
vector<int> colors, positions;    //Vertex -> Color, Vertex -> Offset
vector<int> lengths, parents, branches;    //Color -> Int, Color -> Color, Color -> Offset
vector<int> parentnodes, depths;    //Vertex -> Vertex, Vertex -> Int
//vector<...>????1???????????????sortNodes()??????
vector<int> sortednodes, offsets;    //Index -> Vertex, Color -> Index

//???????????????????????????(???)
void build(const vector<vi> &g, int root) {
int n = g.size();

colors.assign(n, -1); positions.assign(n, -1);
lengths.clear(); parents.clear(); branches.clear();
parentnodes.assign(n, -1); depths.assign(n, -1);

vector<int> subtreesizes;
measure(g, root, subtreesizes);

struct State {
int i, len, parent;
State() { }
State(int i_, int l, int p): i(i_), len(l), parent(p) { }
};
depths[root] = 0;
vector<State> s;
s.push_back(State(root, 0, -1));
while(!s.empty()) {
State t = s.back(); s.pop_back();
int i = t.i, len = t.len;
int color = lengths.size();
if(t.parent != -2) {
assert(parents.size() == color);
parents.push_back(t.parent);
branches.push_back(len);
len = 0;
}
colors[i] = color;
positions[i] = len;

int maxsize = -1, maxj = -1;
each(j, g[i]) if(colors[*j] == -1) {
if(maxsize < subtreesizes[*j]) {
maxsize = subtreesizes[*j];
maxj = *j;
}
parentnodes[*j] = i;
depths[*j] = depths[i] + 1;
}
if(maxj == -1) {
lengths.push_back(len + 1);
}else {
each(j, g[i]) if(colors[*j] == -1 && *j != maxj)
s.push_back(State(*j, len, color));
s.push_back(State(maxj, len + 1, -2));
}
}

sortNodes();
}

void sortNodes() {
int n = colors.size(), m = lengths.size();
sortednodes.resize(n, -1);
offsets.resize(m + 1);
rep(i, m) offsets[i+1] = offsets[i] + lengths[i];
rep(i, n) sortednodes[offsets[colors[i]] + positions[i]] = i;
}

void get(int v, int &c, int &p) const {
c = colors[v]; p = positions[v];
}
bool go_up(int &c, int &p) const {
p = branches[c]; c = parents[c];
return c != -1;
}

inline const int *nodesBegin(int c) const { return &sortednodes[0] + offsets[c]; }
inline const int *nodesEnd(int c) const { return &sortednodes[0] + offsets[c+1]; }

private:
void measure(const vector<vi> &g, int root, vector<int> &out_subtreesizes) const {
out_subtreesizes.assign(g.size(), -1);
vector<int> s;
s.push_back(root);
while(!s.empty()) {
int i = s.back(); s.pop_back();
if(out_subtreesizes[i] == -2) {
int s = 1;
each(j, g[i]) if(out_subtreesizes[*j] != -2)
s += out_subtreesizes[*j];
out_subtreesizes[i] = s;
}else {
s.push_back(i);
each(j, g[i]) if(out_subtreesizes[*j] == -1)
s.push_back(*j);
out_subtreesizes[i] = -2;
}
}
}
};

typedef int Vertex;
struct Graph {
typedef std::pair<Vertex, Vertex> Edge;
struct To {
Vertex to;
};

int n, m;

Graph(int n_, const std::vector<Edge> &edges):
n(n_), m(edges.size()), tos(m+1), offsets(n+1, 0) {
for(int e = 0; e < m; e ++) offsets[edges[e].first] ++;
for(int v = 1; v <= n; v ++) offsets[v] += offsets[v-1];
for(int e = 0; e < m; e ++)
tos[-- offsets[edges[e].first]].to = edges[e].second;
}

inline const To *edgesBegin(int v) const { return &tos[offsets[v]]; }
inline const To *edgesEnd(int v) const { return &tos[offsets[v+1]]; }

inline const int outDegree(int v) const { return offsets[v+1] - offsets[v]; }

private:
std::vector<To> tos;
std::vector<int> offsets;
};

class SchieberVishkinLCA {
public:
typedef unsigned Word;
private:

static inline Word lowestOneBit(Word v) {
return v & (~v+1);
}
static inline Word highestOneBitMask(Word v) {
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
return v >> 1;
}

std::vector<Word> indices;            //Vertex -> index
std::vector<Word> maxHIndices;        //Vertex -> index
std::vector<Word> ancestorHeights;    //Vertex -> Word
std::vector<Vertex> pathParents;    //index-1 -> Vertex
public:
//g?????????????
void build(const Graph &g, Vertex root) {
assert(g.m == g.n - 1);

ancestorHeights.resize(g.n);
std::vector<Vertex> parents(g.n);
maxHIndices.resize(g.n);
std::vector<Vertex> vertices; vertices.reserve(g.n);
indices.resize(g.n);

//euler tour
Word currentIndex = 1;
parents[root] = root;    //???????
vertices.push_back(root);
while(!vertices.empty()) {
Vertex v = vertices.back(); vertices.pop_back();
indices[v] = currentIndex ++;
for(const Graph::To *it = g.edgesBegin(v); it != g.edgesEnd(v); ++ it) {
parents[it->to] = v;
vertices.push_back(it->to);
}
}

//BFS (???????????????)
int head = 0, tail = 1;
vertices.resize(g.n); vertices[0] = root;
for(const Graph::To *it = g.edgesBegin(v); it != g.edgesEnd(v); ++ it)
vertices[tail ++] = it->to;
}

//?????
for(std::vector<Vertex>::const_iterator it = vertices.begin(); it != vertices.end(); ++ it)
maxHIndices[*it] = indices[*it];
for(std::vector<Vertex>::const_reverse_iterator it = vertices.rbegin(); it != vertices.rend(); ++ it) {
Vertex v = *it, parent = parents[v];
if(lowestOneBit(maxHIndices[parent]) < lowestOneBit(maxHIndices[v]))
maxHIndices[parent] = maxHIndices[v];
}

//A????
ancestorHeights[root] = 0;
for(std::vector<Vertex>::const_iterator it = vertices.begin(); it != vertices.end(); ++ it) {
Vertex v = *it;
ancestorHeights[v] = ancestorHeights[parents[v]] | lowestOneBit(maxHIndices[v]);
}

pathParents.swap(parents);    //???????
pathParents[indices[root]-1] = root;
for(std::vector<Vertex>::const_iterator it = vertices.begin(); it != vertices.end(); ++ it) {
Vertex v = *it;
for(const Graph::To *jt = g.edgesBegin(v); jt != g.edgesEnd(v); ++ jt) {
if(maxHIndices[v] != maxHIndices[jt->to])
pathParents[indices[jt->to]-1] = v;
else
pathParents[indices[jt->to]-1] = pathParents[indices[v]-1];
}
}
}

Vertex query(Vertex v, Vertex u) const {
//binary tree???LCA???????
Word Iv = maxHIndices[v], Iu = maxHIndices[u];
Word hIv = lowestOneBit(Iv), hIu = lowestOneBit(Iu);
Word j = lowestOneBit(ancestorHeights[v] & ancestorHeights[u] & ~hbMask);
//j = hI(lca(v,u)) ??? (????hI(x) = 2^(complete binary tree???I(x)???), I(x) = maxHIndices[x])
//(hI(lca(v,u)) = j)?hI(v)?hI(u)????????????????????????…
Vertex x, y;
if(j == hIv) x = v;
else {            //lca?v????????
}
if(j == hIu) y = u;
else {            //lca?u????????
}
return indices[x] < indices[y] ? x : y;    //in-order????????????????????
}
};

void direct_tree(const vector<vi> &g, int i, int parent, vector<pii> &out_edges) {
each(j, g[i]) if(*j != parent) {
out_edges.pb(mp(i, *j));
direct_tree(g, *j, i, out_edges);
}
}

template<int MOD>
struct ModInt {
static const int Mod = MOD;
int x;
ModInt(): x(0) { }
ModInt(signed sig) { if((x = sig % MOD + MOD) >= MOD) x -= MOD; }
ModInt(signed long long sig) { if((x = sig % MOD + MOD) >= MOD) x -= MOD; }
int get() const { return x; }

ModInt &operator+=(ModInt that) { if((x += that.x) >= MOD) x -= MOD; return *this; }
ModInt &operator-=(ModInt that) { if((x += MOD - that.x) >= MOD) x -= MOD; return *this; }
ModInt &operator*=(ModInt that) { x = (unsigned long long)x * that.x % MOD; return *this; }
ModInt &operator/=(ModInt that) { return *this *= that.inverse(); }

ModInt operator+(ModInt that) const { return ModInt(*this) += that; }
ModInt operator-(ModInt that) const { return ModInt(*this) -= that; }
ModInt operator*(ModInt that) const { return ModInt(*this) *= that; }
ModInt operator/(ModInt that) const { return ModInt(*this) /= that; }

ModInt inverse() const {
long long a = x, b = MOD, u = 1, v = 0;
while(b) {
long long t = a / b;
a -= t * b; std::swap(a, b);
u -= t * v; std::swap(u, v);
}
return ModInt(u);
}

bool operator==(ModInt that) const { return x == that.x; }
bool operator!=(ModInt that) const { return x != that.x; }
ModInt operator-() const { ModInt t; t.x = x == 0 ? 0 : Mod - x; return t; }
};
typedef ModInt<100711433> mint;

mint powR[100001], powinvR[100001];
mint up[100001], down[100001];
mint sum[100001];
int main() {
int N, R, invR, U, Q;
scanf("%d%d", &N, &R);
invR = mint(R).inverse().get();
powR[0] = powinvR[0] = 1;
reu(i, 1, N+1) powR[i] = powR[i-1] * R;
reu(i, 1, N+1) powinvR[i] = powinvR[i-1] * invR;
vector<vi> g(N);
rep(i, N-1) {
int a, b;
scanf("%d%d", &a, &b); a --, b --;
g[a].pb(b); g[b].pb(a);
}
vector<pii> edges;
direct_tree(g, 0, -1, edges);
CentroidPathDecomposition cpd; cpd.build(g, 0);
SchieberVishkinLCA lca; lca.build(Graph(N, edges), 0);

mset(up, 0); mset(down, 0);
scanf("%d%d", &U, &Q);
rep(ii, U) {
int a, b, X;
scanf("%d%d%d", &a, &b, &X); a --, b --;
int l = lca.query(a, b);
int c, p, lc, lp;
cpd.get(l, lc, lp);
mint x = X;
cpd.get(a, c, p);
while(1) {
int k = cpd.offsets[c], kp = k + p, k0 = k + (c == lc ? lp : 0);
up[k + p] += x;
x *= powR[kp - k0 + 1];
if(k0) up[k0 - 1] -= x;
if(c == lc) break;
cpd.go_up(c, p);
}
int len = cpd.depths[a] + cpd.depths[b] - cpd.depths[l] * 2;
x = powR[len] * X;
cpd.get(b, c, p);
while(1) {
int k = cpd.offsets[c], kp = k + p, k0 = k + (c == lc ? lp + 1 : 0);
int h = kp - k0 + 1;
mint nx = x * powinvR[h];
down[k0] += nx * R;
down[kp + 1] -= x * R;
if(c == lc) break;
x = nx;
cpd.go_up(c, p);
}
}

for(int i = N-1; i > 0; i --) up[i-1] += up[i] * R;
for(int i = 0;   i < N; i ++) down[i+1] += down[i] * R;
sum[0] = 0;
rep(i, N) sum[i+1] = sum[i] + up[i] + down[i];
rep(ii, Q) {
int a, b;
scanf("%d%d", &a, &b); a --, b --;
int l = lca.query(a, b);
int c, p, lc, lp;
cpd.get(l, lc, lp);
cpd.get(a, c, p);
mint ans = 0;
while(1) {
int k = cpd.offsets[c], kp = k + p, k0 = k + (c == lc ? lp : 0);
ans += sum[kp+1] - sum[k0];
if(c == lc) break;
cpd.go_up(c, p);
}
cpd.get(b, c, p);
while(1) {
int k = cpd.offsets[c], kp = k + p, k0 = k + (c == lc ? lp + 1 : 0);
ans += sum[kp+1] - sum[k0];
if(c == lc) break;
cpd.go_up(c, p);
}
printf("%d\n", ans.get());
}
return 0;
}

## Problem solution in C programming.

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MOD 100711433
typedef struct _lnode
{
int x;
int w;
struct _lnode *next;
}lnode;
typedef struct _tree
{
long long sum;
long long offset1;
long long offset2;
}tree;
int N, cn, level[100000], DP[18][100000], subtree_size[100000], special[100000], node_chain[100000], node_idx[100000], chain_head[100000], chain_len[100000] = {0};
long long p[100001], sp[100001];
lnode *table[100000] = {0};
tree *chain[100000];
void insert_edge(int x, int y, int w)
{
lnode *t=malloc(sizeof(lnode));
t -> x = y;
t -> w = w;
t -> next = table[x];
table[x] = t;
t = malloc(sizeof(lnode));
t -> x = x;
t -> w = w;
t -> next = table[y];
table[y] = t;
return;
}
void dfs0(int u)
{
lnode *x;
subtree_size[u] = 1;
special[u] = -1;
for( x = table[u] ; x ; x = x -> next )
{
if( x -> x != DP[0][u] )
{
DP[0][x -> x] = u;
level[x -> x] = level[u] + 1;
dfs0(x -> x);
subtree_size[u] += subtree_size[x -> x];
if( special[u] == -1 || subtree_size[x -> x] > subtree_size[special[u]] )
{
special[u] = x -> x;
}
}
}
return;
}
void dfs1(int u, int c)
{
lnode *x;
node_chain[u] = c;
node_idx[u] = chain_len[c]++;
for( x = table[u] ; x ; x = x -> next )
{
if( x -> x != DP[0][u] )
{
if( x -> x == special[u] )
{
dfs1(x -> x, c);
}
else
{
dfs1(x -> x, cn++);
}
}
}
return;
}
void preprocess()
{
int i, j;
level[0] = 0;
DP[0][0] = 0;
dfs0(0);
for( i = 1 ; i < 18 ; i++ )
{
for( j = 0 ; j < N ; j++ )
{
DP[i][j] = DP[i-1][DP[i-1][j]];
}
}
cn = 1;
dfs1(0, 0);
for( i = 0 ; i < cn ; i++ )
{
chain[i] = (tree*)malloc(4 * chain_len[i] * sizeof(tree));
memset(chain[i], 0, 4*chain_len[i]*sizeof(tree));
}
return;
}
int lca(int a, int b)
{
int i;
if( level[a] > level[b] )
{
i = a;
a = b;
b = i;
}
int d = level[b] - level[a];
for( i = 0 ; i < 18 ; i++ )
{
if( d & ( 1 << i ) )
{
b = DP[i][b];
}
}
if( a == b )
{
return a;
}
for( i = 17 ; i >= 0 ; i-- )
{
if( DP[i][a] != DP[i][b] )
{
a = DP[i][a], b = DP[i][b];
}
}
return DP[0][a];
}
long long sum(int v, int tl, int tr, int l, int r, tree *t)
{
push(v, tl, tr, t);
if( l > r )
{
return 0;
}
if( l == tl && r == tr )
{
return t[v].sum;
}
int tm = ( tl + tr ) / 2;
return ( sum(v*2, tl, tm, l, min(r, tm), t) + sum(v*2+1, tm+1, tr, max(l, tm+1), r, t) ) % MOD;
}
void range_update(int v, int tl, int tr, int pos1, int pos2, long long o1, long long o2, tree *t)
{
push(v, tl, tr, t);
if( pos2 < tl || pos1 > tr )
{
return;
}
int tm = ( tl + tr ) / 2;
if( pos1 <= tl && pos2 >= tr )
{
t[v].offset1 = o1 * p[tl-pos1] % MOD;
t[v].offset2 = o2 * p[pos2-tr] % MOD;
}
else
{
range_update(v*2, tl, tm, pos1, pos2, o1, o2, t);
range_update(v*2+1, tm+1, tr, pos1, pos2, o1, o2, t);
push(v*2, tl, tm, t);
push(v*2+1, tm+1, tr, t);
t[v].sum = ( t[v*2].sum + t[v*2+1].sum ) % MOD;
}
return;
}
void push(int v, int tl, int tr, tree *t)
{
if( !t[v].offset1 && !t[v].offset2 )
{
return;
}
t[v].sum = ( t[v].sum + ( t[v].offset1 + t[v].offset2 ) * sp[tr-tl] ) % MOD;
if( tl != tr )
{
int tm = ( tl + tr ) / 2;
t[v*2].offset1 = ( t[v*2].offset1 + t[v].offset1 ) % MOD;
t[v*2+1].offset1 = ( t[v*2+1].offset1 + t[v].offset1 * p[tm-tl+1] ) % MOD;
t[v*2].offset2 = ( t[v*2].offset2 + t[v].offset2 * p[tr-tm] ) % MOD;
t[v*2+1].offset2 = ( t[v*2+1].offset2 + t[v].offset2 ) % MOD;
}
t[v].offset1 = t[v].offset2 = 0;
return;
}
void range_solve(int x, int y, long long z)
{
int ca = lca(x, y), ty = y;
long long cac = z % MOD, cay = 0;
while( node_chain[x] != node_chain[ca] )
{
range_update(1, 0, chain_len[node_chain[x]]-1, 0, node_idx[x], 0, cac, chain[node_chain[x]]);
cac = cac * p[node_idx[x]+1] % MOD;
}
range_update(1, 0, chain_len[node_chain[x]]-1, node_idx[ca], node_idx[x], 0, cac, chain[node_chain[x]]);
cac = cac * p[node_idx[x]-node_idx[ca]] % MOD;
while( node_chain[ty] != node_chain[ca] )
{
cay += node_idx[ty] + 1;
}
cay += node_idx[ty] - node_idx[ca];
while( node_chain[y] != node_chain[ca] )
{
cay -= node_idx[y];
range_update(1, 0, chain_len[node_chain[y]]-1, 0, node_idx[y], cac*p[cay]%MOD, 0, chain[node_chain[y]]);
cay--;
}
if( node_idx[y] != node_idx[ca] )
{
range_update(1, 0, chain_len[node_chain[y]]-1, node_idx[ca]+1, node_idx[y], cac*p[1]%MOD, 0, chain[node_chain[y]]);
}
return;
}
int min(int x, int y)
{
return ( x < y ) ? x : y ;
}
int max(int x, int y)
{
return ( x > y ) ? x : y;
}
long long solve(int x, int ancestor)
{
long long ans = 0;
while( node_chain[x] != node_chain[ancestor] )
{
ans = ( ans + sum(1, 0, chain_len[node_chain[x]]-1, 0, node_idx[x], chain[node_chain[x]]) ) % MOD;
}
ans = ( ans + sum(1, 0, chain_len[node_chain[x]]-1, node_idx[ancestor], node_idx[x], chain[node_chain[x]]) ) % MOD;
return ans;
}
int main()
{
int U, Q, x, y, i;
long long R, t;
scanf("%d%lld", &N, &R);
R %= MOD;
p[0] = sp[0] = 1;
for( i = 1 ; i <= N ; i++ )
{
p[i] = R * p[i-1] % MOD;
sp[i] = ( sp[i-1] + p[i] ) % MOD;
}
for( i = 0 ; i < N - 1 ; i++ )
{
scanf("%d%d", &x, &y);
insert_edge(x-1, y-1, 1);
}
preprocess();
scanf("%d%d", &U, &Q);
while(U--)
{
scanf("%d%d%lld", &x, &y, &t);
range_solve(x-1, y-1, t);
}
while(Q--)
{
scanf("%d%d", &x, &y);
i = lca(x-1, y-1);
printf("%lld\n", ( solve(x-1, i) + solve(y-1, i) - sum(1, 0, chain_len[node_chain[i]]-1, node_idx[i], node_idx[i], chain[node_chain[i]]) + MOD ) % MOD);
}
return 0;
}