#include <iostream>
#include <vector>
#define inline inline __attribute__((always_inline))
using namespace std;
constexpr int N = 1e5 + 5;
long long weights[N];
vector<pair<int, int>> tree[N];
enum class Type {
Compress,
Vertex,
AddVertex,
Rake,
AddEdge
};
struct Node;
struct NodePtr {
int id;
inline NodePtr() { }
inline NodePtr(int id) : id(id) { }
inline operator bool() const { return id != 0; }
inline Node *operator->() const;
};
struct Node {
NodePtr parent;
NodePtr left, right;
Type type;
struct Data {
long long d, du, dv, duv;
inline void compress(const Data &left, const Data &right) {
d = max(max(left.d, right.d), left.dv + right.du);
du = max(left.du, left.duv + right.du);
dv = max(right.dv, right.duv + left.dv);
duv = left.duv + right.duv;
}
inline void add_vertex(const Data &child, int e) {
duv = weights[e];
dv = child.du;
du = dv + weights[e];
d = max(child.d, du);
}
void vertex(int e) {
d = du = duv = weights[e];
dv = 0;
}
inline void rake(const Data &left, const Data &right) {
d = max(max(left.d, right.d), left.du + right.du);
du = max(left.du, right.du);
}
inline void add_edge(const Data &child) {
d = child.d;
du = child.du;
}
friend ostream &operator<<(ostream &dest, const Data &data) {
return dest << "Data(d=" << data.d << ", du=" << data.du << ", dv=" << data.dv << ", duv=" << data.duv << ")";
}
} data;
inline void pull(int id) {
switch (type)
{
case Type::Compress:
data.compress(left->data, right->data);
// cout << "hi Compress " << id << " data=" << data << endl;
return;
case Type::Vertex:
data.vertex(id);
// cout << "hi Vertex " << id << " data=" << data << endl;
return;
case Type::AddVertex:
data.add_vertex(left->data, id);
// cout << "hi AddVertex " << id << " data=" << data << endl;
return;
case Type::Rake:
data.rake(left->data, right->data);
// cout << "hi Rake " << id << " data=" << data << endl;
return;
case Type::AddEdge:
data.add_edge(left->data);
// cout << "hi AddEdge " << id << " data=" << data << endl;
return;
}
}
};
Node pool[4 * N];
int num_nodes;
inline Node *NodePtr::operator->() const {
return &pool[id];
}
inline NodePtr new_node(int id, NodePtr left, NodePtr right, Type type) {
NodePtr node{id};
left->parent = right->parent = node;
node->left = left;
node->right = right;
node->type = type;
return node;
}
int dfs(int u, int p) {
int size = 1;
int heavy_size = 0;
for (int it = 0; it < tree[u].size(); ) {
int v = tree[u][it].first;
if (v == p) {
swap(tree[u][it], tree[u].back());
tree[u].pop_back();
continue;
}
int child_size = dfs(v, u);
if (child_size > heavy_size) {
heavy_size = child_size;
swap(tree[u][it], tree[u].front());
}
size += child_size;
it++;
}
return size;
}
struct Cluster {
NodePtr node;
int size;
};
Cluster decompress(int, int);
Cluster remove_vertex(int, int);
Cluster split(int);
Cluster remove_edge(int, int);
template <Type type>
Cluster merge(vector<Cluster>::iterator first,
vector<Cluster>::iterator last) {
if (last - first == 1) return *first;
int total_size = 0;
for (auto it = first; it != last; ++it) {
total_size += it->size;
}
auto mid = first;
int left_size = 0;
while (left_size * 2 + mid->size < total_size) {
left_size += mid->size;
++mid;
}
NodePtr node = new_node(++num_nodes,
merge<type>(first, mid).node,
merge<type>(mid, last).node,
type);
node->pull(0);
return {node, total_size};
}
Cluster decompress(int u, int e) {
int orig_u = u;
vector<Cluster> children = {remove_vertex(u, e)};
while (!tree[u].empty()) {
int e = tree[u].front().second;
u = tree[u].front().first;
children.push_back(remove_vertex(u, e));
}
return merge<Type::Compress>(children.begin(), children.end());
}
inline Cluster remove_vertex(int u, int e) {
auto [node, size] = split(u);
node = new_node(e, node, 0, node ? Type::AddVertex : Type::Vertex);
node->pull(e);
return {node, size + 1};
}
inline Cluster split(int u) {
vector<Cluster> children;
for (int it = 1; it < tree[u].size(); it++) {
children.push_back(remove_edge(tree[u][it].first, tree[u][it].second));
}
return children.empty() ? Cluster{0, 0}
: merge<Type::Rake>(children.begin(), children.end());
}
inline Cluster remove_edge(int u, int e) {
auto [node, size] = decompress(u, e);
node = new_node(++num_nodes, node, 0, Type::AddEdge);
node->pull(0);
return {node, size};
}
NodePtr root;
inline void init(int n) {
num_nodes = n;
dfs(1, 1);
root = decompress(1, n).node;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
// freopen("input.txt", "r", stdin);
int n, q;
long long W;
cin >> n >> q >> W;
for (int e = 1; e < n; e++) {
int u, v;
cin >> u >> v >> weights[e];
tree[u].emplace_back(v, e);
tree[v].emplace_back(u, e);
}
init(n);
cout << root->data.d << '\n';
// cout << "dia = " << root->data.d << endl;
long long last = 0;
while (q--) {
int e;
long long w;
cin >> e >> w;
e = (e + last) % (n - 1) + 1;
weights[e] = (w + last) % W;
for (NodePtr node{e}; node; node = node->parent) {
node->pull(node.id);
}
last = root->data.d;
cout << last << '\n';
}
return 0;
}