This submission is migrated from previous version of oj.uz, which used different machine for grading. This submission may have different result if resubmitted.
#include <bits/stdc++.h>
using namespace std;
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
 
template<typename T> using ordered_set = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;
template<typename T, typename U> using ordered_map = tree<T, U, less<T>, rb_tree_tag, tree_order_statistics_node_update>;
 
typedef long long ll;
typedef long double ld;
 
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
 
typedef vector<int> vi;
typedef vector<ll> vll;
 
#define FOR(i,j,k,in) for(int i=(j); i < (k);i+=in)
#define FORD(i,j,k,in) for(int i=(j); i >=(k);i-=in)
#define REP(i,b) FOR(i,0,b,1)
#define REPD(i,b) FORD(i,b,0,1)
#define pb push_back
#define mp make_pair
#define ff first
#define ss second
#define all(x) begin(x), end(x)
#define MANY_TESTS int tcase; cin >> tcase; while(tcase--)
 
const double EPS = 1e-9;
const int MOD = 1e9+7;
const ll INFF = 1e18;
const int INF = 1e9;
const ld PI = acos((ld)-1);
const vi dy = {1, 0, -1, 0, -1, 1, 1, -1};
const vi dx = {0, 1, 0, -1, -1, 1, -1, 1};
 
void DBG(){cout << "]" << endl;}
template<typename T, typename ...U> void DBG(const T& head, const U... args){ cout << head << "; "; DBG(args...); }
#define dbg(...) cout << "Line(" << __LINE__ << ") -> [" << #__VA_ARGS__ << "]: [", DBG(__VA_ARGS__);
#define chk() cout << "Check at line(" << __LINE__ << ") hit." << endl;
 
template<class T, unsigned int U>
ostream& operator<<(ostream& out, const array<T, U> &v){out << "[";  REP(i, U) out << v[i] << ", ";  out << "]"; return out;}
template <class T, class U>
ostream& operator<<(ostream& out, const pair<T, U> &par) {out << "[" << par.first << ";" << par.second << "]"; return out;}
template <class T>
ostream& operator<<(ostream& out, const set<T> &cont) { out << "{"; for( const auto &x:cont) out << x << ", "; out << "}"; return out; }
template <class T, class U>
ostream& operator<<(ostream& out, const map<T, U> &cont) {out << "{"; for( const auto &x:cont) out << x << ", "; out << "}"; return out; }
template<class T>
ostream& operator<<(ostream& out, const vector<T> &v){ out << "[";  REP(i, v.size()) out << v[i] << ", ";  out << "]"; return out;}
 
template<class T>
istream& operator>>(istream& in, vector<T> &v){ for(auto &x : v) in >> x; return in; }
 
struct node{
    ll ans = 0, lazy = 0;
    void apply(int l, int r, ll val){
        ans += val;
        lazy += val;
    }
};
struct segtree{
    node comb(node const &a, node const &b){
        node res;
        res.ans = max(a.ans, b.ans);
        return res;
    }
    void push(int l, int r, int v){
      	if(tree[v].lazy == 0) return;
        tree[v<<1].lazy += tree[v].lazy;
        tree[v<<1|1].lazy += tree[v].lazy;
        tree[v<<1].ans += tree[v].lazy;
        tree[v<<1|1].ans += tree[v].lazy;
        tree[v].lazy = 0;
    }
    int sz;
    vector<node> tree;
    segtree(){}
    segtree(int _sz){ // tree is resized to default values set in node
        sz = 1; while(sz < _sz) sz<<=1;
        tree.resize(2*sz);
    }
    void build(vector<node> &init){
        for(int i = 0; i < sz; ++i)
            if(i < init.size())
                tree[i+sz] = init[i];
        for(int i = sz-1; i > 0; --i)
            tree[i] = comb(tree[i<<1], tree[i<<1|1]);
    }
    node query(int l, int r){return query0(l, r, 0, sz, 1);}
    node query0(int l, int r, int beg, int end, int v){
        if(beg >= l && end <= r)
            return tree[v];
        push(beg, end, v);
        int mid = (beg + end) >> 1;
        node res;
        if(beg >= r || mid <= l) res = query0(l, r, mid, end, v<<1|1); //[beg, mid]
        else if(mid >= r || end <= l) res = query0(l, r, beg, mid, v<<1);
        else res = comb(query0(l, r, beg, mid, v<<1), query0(l, r, mid, end, v<<1|1));
        return res;
    }
    template<typename... T>
    void upd(int l, int r, T ...args){upd0(l, r, 0, sz, 1, args...);}
    template<typename... T>
    void upd0(int l, int r, int beg, int end, int v, T ...args){
        if(beg >= r || end <= l)
            return;
        if(beg >= l && end <= r){
            tree[v].apply(beg, end, args...);
            return;
        }
        push(beg, end, v);
        int mid = (beg + end) >> 1;
        upd0(l, r, beg, mid, v<<1, args...);
        upd0(l, r, mid, end, v<<1|1, args...);
        tree[v] = comb(tree[v<<1], tree[v<<1|1]);
    }
};
 
 
int main(){
 	ios_base::sync_with_stdio(false);
 	cin.tie(NULL); cout.tie(NULL);
    int n, q; ll w;
    cin >> n >> q; cin >> w;
    vector<vector<array<ll, 2>>> g(n);
    vector<array<ll, 3>> edges(n - 1);
    // centroids for full, but too hard to impl, impl at the end if time
    REP(i, n - 1){
        ll a, b, c;
        cin >> a >> b >> c;
        a--; b--;
        g[a].pb({b, i});
        g[b].pb({a, i});
        edges[i] = {a, b, c};
    }
    auto solve12 = [&](){
        int diam1, diam2;
        vector<ll> dist(n, 0);
        function<void(int, int)> dfs = [&](int v, int p){
            for(auto x : g[v]){
                if(x[0] == p) continue;
                ll weight = edges[x[1]][2];
                dist[x[0]] = dist[v] + weight;
                dfs(x[0], v);
            }
        };
        dfs(0, -1); diam1 = max_element(all(dist)) - dist.begin();
        dist[diam1] = 0; dfs(diam1, -1); diam2 = max_element(all(dist)) - dist.begin();
        ll last = 0;
        REP(i, q){
            ll d, e;
            cin >> d >> e;
            d = (d + last) % (n - 1);
            e = (e + last) % w;
            edges[d][2] = e;
            dist[diam1] = 0;
            dfs(diam1, -1); int nxt_diam2 = max_element(all(dist)) - dist.begin();
            ll nxt_diamw2 = *max_element(all(dist));
            dist[diam2] = 0; dfs(diam2, -1); int nxt_diam1 = max_element(all(dist)) - dist.begin();
            ll nxt_diamw1 = *max_element(all(dist));
            if(nxt_diamw1 > nxt_diamw2){
                last = nxt_diamw1;
                diam1 = nxt_diam1;
            }
            else{
                last = nxt_diamw2;
                diam2 = nxt_diam2;
            }
            cout << last << "\n";
        }
    };
    //solve12();
    auto solve = [&](){
        vector<multiset<ll>> depths(n); // for each centroid
        multiset<ll> answers;
        vector<int> par(n, -1); // parent in centroid tree
        vector<int> lev(n, 0); // level of centroid
        const int mxlv = 19;
        vector<vector<int>> in(mxlv, vector<int>(n, -1));
        vector<vector<int>> out(mxlv, vector<int>(n, -1));
        vector<vector<int>> sub_root(mxlv, vector<int>(n, -1));
        vector<segtree> segtrees(n);
        vector<bool> dead(n, false);
        vector<int> sub(n, 0);
        auto compute_ans = [](multiset<ll> &se){
            multiset<ll> :: reverse_iterator it = se.rbegin();
            if(se.size() == 0) return 0ll;
            ll res = *it;
            if(se.size() > 1){
                it++; res += *it;
            }
            return res;
        };
        function<void(int, int)> getsub = [&](int v, int p){
            sub[v] = 1;
            for(auto x : g[v]){
                if(x[0] == p) continue;
                if(dead[x[0]]) continue;
                getsub(x[0], v);
                sub[v] += sub[x[0]];
            }
        };
        function<int(int, int, int)> get_centroid = [&](int v, int p, int total_size){
            int heavy_child = -1;
            for(auto x : g[v]){
                if(x[0] == p || dead[x[0]]) continue;
                if(sub[x[0]] > total_size / 2)
                    heavy_child = x[0];
            }
            if(heavy_child == -1)
                return v;
            else
                return get_centroid(heavy_child, v, total_size);
        };
 
        function<void(int, int)> decompose = [&](int v, int p){
            // find centroid of this subtree
            getsub(v, -1);
            int centroid = get_centroid(v, -1, sub[v]);
            par[centroid] = p; // par in centroid tree
            if(p != -1) lev[centroid] = lev[p] + 1;
            int t = 0;
            segtrees[centroid] = segtree(sub[v]);
            vector<node> init(sub[v]);
            int level = lev[centroid];
            function<void(int, int, ll, int)> dfs = [&](int v, int p, ll depth, int subrootnum){
                in[level][v] = t; init[t].ans = depth;
                sub_root[level][v] = subrootnum;
                t++;
                for(auto x : g[v]){
                    if(x[0] == p || dead[x[0]]) continue;
                    ll weight = edges[x[1]][2];
                    dfs(x[0], v, depth + weight, subrootnum);
                }
                out[level][v] = t;
            };
            for(auto x : g[centroid]){
                if(dead[x[0]]) continue;
                ll weight = edges[x[1]][2];
                dfs(x[0], centroid, weight, x[0]);
            }
            segtrees[centroid].build(init);
            for(auto x : g[centroid]){
                if(dead[x[0]]) continue;
                depths[centroid].insert(segtrees[centroid].query(in[level][x[0]], out[level][x[0]]).ans);
            }
            answers.insert(compute_ans(depths[centroid]));
            dead[centroid] = true;
            for(auto x : g[centroid]){
                if(dead[x[0]]) continue;
                decompose(x[0], centroid);
            }
        };
        decompose(0, -1);
        ll last = 0;
        REP(i, q){
            ll d, e;
            cin >> d >> e;
            d = (d + last) % (n - 1);
            e = (e + last) % w;
            auto edge = edges[d];
            int frs; // prvy centroid ktoreho sa to dotkne
            if(lev[edge[0]] < lev[edge[1]])
                frs = edge[0];
            else
                frs = edge[1];
            while(frs != -1){
                answers.erase(answers.find(compute_ans(depths[frs])));
                int centroid_lev = lev[frs];
                int desc;
                if(in[centroid_lev][edge[0]] > in[centroid_lev][edge[1]])
                    desc = edge[0];
                else
                    desc = edge[1];
                ll delta = e - edge[2];
                int root = sub_root[centroid_lev][desc];
                depths[frs].erase(depths[frs].find(segtrees[frs].query(in[centroid_lev][root], out[centroid_lev][root]).ans));
                segtrees[frs].upd(in[centroid_lev][desc], out[centroid_lev][desc], delta);
                depths[frs].insert(segtrees[frs].query(in[centroid_lev][root], out[centroid_lev][root]).ans);
                answers.insert(compute_ans(depths[frs]));
                frs = par[frs];
            }
            edges[d][2] = e;
            last = *answers.rbegin();
            cout << last << "\n";
        }
    };
    solve();
    return 0;
}
Compilation message (stderr)
diameter.cpp: In member function 'void segtree::build(std::vector<node>&)':
diameter.cpp:87:18: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<node>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
   87 |             if(i < init.size())
      |                ~~^~~~~~~~~~~~~
diameter.cpp: In function 'int main()':
diameter.cpp:139:10: warning: variable 'solve12' set but not used [-Wunused-but-set-variable]
  139 |     auto solve12 = [&](){
      |          ^~~~~~~| # | 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... |