#include <bits/stdc++.h>
#define int long long
#define fi first
#define se second
#define sz(a) (int)((a).size())
#define all(a) (a).begin(), (a).end()
#define lsb(x) (x & (-x))
#define vi vector<int>
#define YES { cout << "YES" << endl; return; }
#define NO { cout << "NO" << endl; return; }
using ll = long long;
using pii = std::pair<int, int>;
const int NMAX = 1e5;
const int INF = 1e16;
using namespace std;
namespace DynamicDiameter {
vector<pair<int, int>> T[NMAX + 5];
int event[2 * NMAX + 5], timer = 0;
int weights[NMAX + 5], dep[NMAX + 5];
int tin[NMAX + 5], tout[NMAX + 5];
inline void add_edge(int u, int v, int w) {
T[u].push_back({v, w});
T[v].push_back({u, w});
}
void dfs(int nod, int p = -1) {
tin[nod] = ++timer;
event[timer] = nod;
for (auto &[son, w] : T[nod]) {
if (son == p) continue;
dep[son] = dep[nod] + w;
weights[son] = w;
dfs(son, nod);
event[++timer] = nod;
}
tout[nod] = timer;
}
struct node_t {
pair<int, int> max_depth;
pair<int, int> min_depth;
pair<int, int> ab;
pair<int, int> bc;
int diam;
bool is_null;
node_t() : max_depth({-INF, -1}), min_depth({INF, -1}), ab({-INF, -1}), bc({-INF, -1}), diam(0), is_null(true) {}
static node_t merge(const node_t l, const node_t r) {
if (l.is_null) return r;
if (r.is_null) return l;
node_t res;
res.is_null = false;
res.max_depth = max(l.max_depth, r.max_depth);
res.min_depth = min(l.min_depth, r.min_depth);
res.ab = max({l.ab, r.ab, {l.max_depth.fi - 2 * r.min_depth.fi, r.max_depth.se}});
res.bc = max({l.bc, r.bc, {r.max_depth.fi - 2 * l.min_depth.fi, l.max_depth.se}});
res.diam = max({l.diam, r.diam, l.max_depth.fi + r.bc.fi, r.max_depth.fi + l.ab.fi});
return res;
}
};
node_t aint[8 * NMAX + 5];
int lazy[8 * NMAX + 5];
void build(int nod = 1, int st = 1, int dr = timer) {
if (st == dr) {
int u = event[st];
aint[nod].is_null = false;
aint[nod].max_depth = aint[nod].min_depth = {dep[u], u};
aint[nod].ab = aint[nod].bc = {-dep[u], u};
aint[nod].diam = 0;
lazy[nod] = 0;
return;
}
int m = (st + dr) >> 1;
build(2 * nod, st, m);
build(2 * nod + 1, m + 1, dr);
aint[nod] = node_t::merge(aint[2 * nod], aint[2 * nod + 1]);
lazy[nod] = 0;
}
void init() {
dfs(1);
build();
}
void push(int nod, int st, int dr) {
if (lazy[nod] != 0) {
int& lz = lazy[nod];
aint[nod].max_depth.fi += lz;
aint[nod].min_depth.fi += lz;
aint[nod].ab.fi -= lz;
aint[nod].bc.fi -= lz;
if (st != dr) {
lazy[2 * nod] += lz;
lazy[2 * nod + 1] += lz;
}
lazy[nod] = 0;
}
}
void range_add(int l, int r, int v, int nod = 1, int st = 1, int dr = timer) {
push(nod, st, dr);
if (st > r || dr < l) return;
if (l <= st && dr <= r) {
lazy[nod] += v;
push(nod, st, dr);
return;
}
int m = (st + dr) >> 1;
range_add(l, r, v, 2 * nod, st, m);
range_add(l, r, v, 2 * nod + 1, m + 1, dr);
aint[nod] = node_t::merge(aint[2 * nod], aint[2 * nod + 1]);
}
void AssignEdgeWeight(int u, int v, int e) {
if (tin[u] > tin[v]) swap(u, v);
int diff = e - weights[v];
range_add(tin[v], tout[v], diff);
weights[v] = e;
}
int get_diam() {
return aint[1].diam;
}
}
using namespace DynamicDiameter;
pair<int, int> edges[NMAX + 5];
int n, q, mod;
signed main() {
cin.tie(nullptr)->sync_with_stdio(false);
cin >> n >> q >> mod;
for (int i = 0, u, v, w; i < n - 1; ++i) {
cin >> u >> v >> w;
edges[i] = {u, v};
DynamicDiameter::add_edge(u, v, w);
}
DynamicDiameter::init();
for (int i = 0, d, e, last = 0; i < q; ++i) {
cin >> d >> e;
d = (d + last) % (n - 1);
e = (e + last) % mod;
auto [u, v] = edges[d];
DynamicDiameter::AssignEdgeWeight(u, v, e);
last = DynamicDiameter::get_diam();
cout << last << "\n";
}
return 0;
}