#include <bits/stdc++.h>
using namespace std;
#define task "DIAMETER"
#define FOR(i, a, b) for (int i = (a); i <= (b); i++)
#define FOD(i, a, b) for (int i = (a); i >= (b); i--)
#define F first
#define S second
#define ll long long
typedef pair<int, int> ii;
const int N = (int)1e5 + 5;
int numNode, numQuery;
ll limit;
struct EDGE {
    int u, v;
    ll w;
};
vector<ii> adj[N];
EDGE edges[N];
int sz[N];
bool del[N];
vector<ii> ancestors[N]; // storing ancestors of current node: {anc, DFS time of current node}
multiset<ll> candidates;
struct TREE {
    vector<ll> tree, lazy, dist;
    vector<int> directSon; // storing the son which is an ancestor of current node and directly connected with the root
    vector<ii> sons; // storing sons of current node with its DFS time
    vector<int> out;
    int n, root;
    void init() {
        tree.assign(4 * n + 3, 0);
        lazy.assign(4 * n + 3, 0);
        dist.assign(n + 2, 0);
        out.resize(n + 2);
        directSon.resize(n + 2);
    }
    // SEGMENT TREE LAZY UPDATE + MAX QUERY
    void build(int id, int l, int r) {
        if (l == r) {
            tree[id] = dist[l];
            return;
        }
        int mid = (l + r) >> 1;
        build(2 * id, l, mid);
        build(2 * id + 1, mid + 1, r);
        tree[id] = max(tree[2 * id], tree[2 * id + 1]);
    }
    void down(int id) {
        if (lazy[id] == 0) return;
        FOR(i, 2 * id, 2 * id + 1) {
            tree[i] += lazy[id];
            lazy[i] += lazy[id];
        }
        lazy[id] = 0;
    }
    void update(int id, int l, int r, int u, int v, ll val) {
        if (l > v || r < u) return;
        if (l >= u && r <= v) {
            tree[id] += val;
            lazy[id] += val;
            return;
        }
        down(id);
        int mid = (l + r) >> 1;
        update(2 * id, l, mid, u, v, val);
        update(2 * id + 1, mid + 1, r, u, v, val);
        tree[id] = max(tree[2 * id], tree[2 * id + 1]);
    }
    void update(int u, int v, ll val) {
        update(1, 1, n, u, v, val);
    }
    ll get(int id, int l, int r, int u, int v) {
        if (l > v || r < u) return 0;
        if (l >= u && r <= v) return tree[id];
        down(id);
        int mid = (l + r) >> 1;
        return max(get(2 * id, l, mid, u, v), get(2 * id + 1, mid + 1, r, u, v));
    }
    ll get(int l, int r) {
        return get(1, 1, n, l, r);
    }
    // BUILD TREE
    int timer = 0;
    multiset<ll> values;
    void dfs(int u, int p) {
        int in = ++timer;
        ancestors[u].push_back({root, timer});
        sons.push_back({u, timer});
        for (ii e : adj[u]) {
            int v = e.F;
            ll w = e.S;
            if (v == p || del[v]) continue;
            dist[timer + 1] = dist[in] + w;
            directSon[timer + 1] = (p == -1 ? timer + 1 : directSon[timer]);
            dfs(v, u);
        }
        out[in] = timer;
    }
    int ID(int node) {
        return lower_bound(sons.begin(), sons.end(), make_pair(node, 0)) - sons.begin();
    }
    ll best(multiset<ll> s) {
        if (s.size() == 1) return *s.begin();
        auto it = prev(s.end());
        return *it + *(prev(it));
    }
    void construct(int u, int _n) {
        root = u, n = _n;
        init();
        dfs(u, -1);
        build(1, 1, n);
        sort(sons.begin(), sons.end());
        for (ii e : adj[u]) {
            int v = e.F;
            ll w = e.S;
            if (del[v]) continue;
            int ID_V = ID(v), in = sons[ID_V].S;
            values.insert(get(in, out[in]));
        }
        candidates.insert(best(values));
    }
    void change(int ID_U, ll val, int v) {
        int ID_V = ID(v);
        if (ID_V == n || sons[ID_V].F != v) return;
        ID_V = sons[ID_V].S;
        if (ID_V < ID_U) swap(ID_U, ID_V);
        ll x = best(values);
        candidates.erase(candidates.find(x));
        int in = directSon[ID_V];
        x = get(in, out[in]);
        values.erase(values.find(x));
        update(ID_V, out[ID_V], val);
        x = get(in, out[in]);
        values.insert(x);
        x = best(values);
        candidates.insert(x);
    } 
} tree[N];
int countChild(int u, int p) {
    sz[u] = 1;
    for (ii e : adj[u]) {
        int v = e.F;
        if (v == p || del[v]) continue;
        sz[u] += countChild(v, u);
    }
    return sz[u];
}
int centroid(int u, int p, int m) {
    for (ii e : adj[u]) {
        int v = e.F;
        if (v == p || del[v]) continue;
        if (sz[v] > m / 2) return centroid(v, u, m);
    }
    return u;
}
void decompose(int u, int p) {
    int x = centroid(u, -1, countChild(u, -1));
    del[x] = 1;
    if (sz[u] > 1) tree[x].construct(x, sz[u]);
    for (ii e : adj[x]) {
        int v = e.F;
        if (del[v]) continue;
        decompose(v, x);
    }
}
int main() {
    if (fopen(task".inp", "r")) {
        freopen(task".inp", "r", stdin);
        freopen(task".out", "w", stdout);
    }
    ios_base::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    cin >> numNode >> numQuery >> limit;
    FOR(i, 1, numNode - 1) {
        int u, v;
        ll w;
        cin >> u >> v >> w;
        adj[u].push_back({v, w});
        adj[v].push_back({u, w});
        edges[i] = {u, v, w};
    }
    decompose(1, -1);
    // return 0;
    ll last = 0;
    while (numQuery--) {
        ll edgeID, newW;
        cin >> edgeID >> newW;
        edgeID = (edgeID + last) % (numNode - 1) + 1;
        newW = (newW + last) % limit;
        for (ii r : ancestors[edges[edgeID].u]) {
            int root = r.F, ID_U = r.S;
            tree[root].change(ID_U, -edges[edgeID].w + newW, edges[edgeID].v);
        } 
        edges[edgeID].w = newW;
        cout << (last = *(candidates.rbegin())) << "\n";
    }
    return 0;
}
Compilation message (stderr)
diameter.cpp: In function 'int main()':
diameter.cpp:196:16: warning: ignoring return value of 'FILE* freopen(const char*, const char*, FILE*)' declared with attribute 'warn_unused_result' [-Wunused-result]
  196 |         freopen(task".inp", "r", stdin);
      |         ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
diameter.cpp:197:16: warning: ignoring return value of 'FILE* freopen(const char*, const char*, FILE*)' declared with attribute 'warn_unused_result' [-Wunused-result]
  197 |         freopen(task".out", "w", stdout);
      |         ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~| # | Verdict  | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict  | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict  | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict  | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict  | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict  | Execution time | Memory | Grader output | 
|---|
| Fetching results... |