#include using namespace std; #ifdef LOCAL ifstream fin("suceava.in"); ofstream fout("suceava.out"); #else #define fin cin #define fout cout #endif const int kN = 1e5; const int kM = 1e5; const int kT = 1e5; const int kQ = 1e5; const int kLog = 18; const int kInf = 1e9; const bool ERASE = 0; const bool INSERT = 1; vector adj[kN], rmq[kLog + 1]; int tin[kN], depth[kN], lg2[kN << 1 | 1]; void maxSelf(int &x, int y) { if(y > x) { x = y; } } void dfs(int u = 0, int v = 0) { tin[u] = rmq[0].size(); rmq[0].emplace_back(u); for(const auto &it: adj[u]) if(it != v) { depth[it] = depth[u] + 1; dfs(it, u); rmq[0].emplace_back(u); } } int _min(int u, int v) { if(depth[u] < depth[v]) { return u; } return v; } void init() { dfs(); lg2[1] = 0; for(int i = 2; i <= (int) rmq[0].size(); i++) { lg2[i] = lg2[i >> 1] + 1; } int n = rmq[0].size(); for(int i = 1; (1 << i) <= n; i++) { for(int j = 0; j + (1 << i) - 1 < n; j++) { rmq[i].emplace_back(_min(rmq[i - 1][j], rmq[i - 1][j + (1 << (i - 1))])); } } } int query(int l, int r) { int lg = lg2[r - l + 1]; return _min(rmq[lg][l], rmq[lg][r - (1 << lg) + 1]); } int lca(int u, int v) { int l = tin[u], r = tin[v]; if(l > r) { swap(l, r); } return query(l, r); } int dist(int u, int v) { return depth[u] + depth[v] - 2 * depth[lca(u, v)]; } struct Edge { int u, v; Edge() {} Edge(int u, int v): u(u), v(v) {} bool operator < (const Edge &oth) const { if(u == oth.u) { return v < oth.v; } return u < oth.u; } }; map col; struct Event { bool t; int time; Edge edge; Event(bool t, int time, Edge edge): t(t), time(time), edge(edge) {} }; vector events[kN]; vector> res[kN]; struct DSU { struct DSU_SAVE { int u, v; pair diameter; DSU_SAVE() {} DSU_SAVE(int u, int v, pair diameter): u(u), v(v), diameter(diameter) {} }; int n; vector par, sz; vector> diameter; stack stk; int mx; DSU() {} DSU(int n): n(n), par(n), sz(n), diameter(n) { init(); } void init() { assert(stk.empty()); mx = 0; for(int i = 0; i < n; i++) { makeSet(i); } } void makeSet(int u) { par[u] = u; sz[u] = 1; diameter[u] = make_pair(u, u); } int findRoot(int u) { if(par[u] == u) { return u; } return findRoot(par[u]); } pair findDiameter(int u) { return diameter[findRoot(u)]; } pair join(int u, int v) { pair t1 = findDiameter(u); pair t2 = findDiameter(v); vector> candidates = { t1, t2, {t1.first, t2.first}, {t1.first, t2.second}, {t1.second, t2.first}, {t1.second, t2.second} }; int max_dist = 0; pair res = candidates.front(); for(const auto &it: candidates) { if(dist(it.first, it.second) > max_dist) { res = it; max_dist = dist(it.first, it.second); } } maxSelf(mx, max_dist); return res; } bool unite(int u, int v) { u = findRoot(u); v = findRoot(v); if(u == v) { return 0; } if(sz[u] > sz[v]) { swap(u, v); } stk.emplace(u, v, diameter[v]); diameter[v] = join(u, v); par[u] = v; sz[v] += sz[u]; return 1; } void undo() { assert(!stk.empty()); int u = stk.top().u, v = stk.top().v; pair old_diameter = stk.top().diameter, crt_diameter = diameter[v]; int crt_dist = dist(crt_diameter.first, crt_diameter.second); stk.pop(); par[u] = u; sz[v] -= sz[u]; diameter[v] = old_diameter; } void undo_max(int newVal) { mx = newVal; } int query() { return mx; } }; DSU dsu; vector ans; struct AINT { int n; vector> tree; AINT() {} AINT(int n): n(n), tree(n << 2 | 1) {} void update(int a, int b, const Edge &edge, int node, int l, int r) { if(a <= l && r <= b) { tree[node].emplace_back(edge); } else { int mid = (l + r) >> 1; if(a <= mid) { update(a, b, edge, node << 1, l, mid); } if(b > mid) { update(a, b, edge, node << 1 | 1, mid + 1, r); } } } void update(int a, int b, const Edge &edge) { update(a, b, edge, 1, 0, n); } void solve(int node, int l, int r) { int cnt = 0, prev_max = dsu.query(); for(const auto &it: tree[node]) { cnt += dsu.unite(it.u, it.v); } if(l == r) { ans[l] = dsu.query(); } else { int mid = (l + r) >> 1; solve(node << 1, l, mid); solve(node << 1 | 1, mid + 1, r); } while(cnt--) { dsu.undo(); } dsu.undo_max(prev_max); } void solve() { ans = vector(n + 1); solve(1, 0, n); } }; int main() { fin.tie(nullptr)->sync_with_stdio(false); int n, m; assert(fin >> n >> m); assert(2 <= n && n <= kN); assert(2 <= m && m <= kM); dsu = DSU(n); for(int i = 1; i < n; i++) { int u, v, c; assert(fin >> u >> v >> c); assert(1 <= u && u <= n); assert(1 <= v && v <= n); assert(1 <= c && c <= m); u--; v--; c--; if(u > v) { swap(u, v); } col[Edge(u, v)] = c; events[c].emplace_back(INSERT, 0, Edge(u, v)); adj[u].emplace_back(v); adj[v].emplace_back(u); } int t; assert(fin >> t); assert(1 <= t && t <= kT); for(int i = 1; i <= t; i++) { int u, v, c; assert(fin >> u >> v >> c); assert(1 <= u && u <= n); assert(1 <= v && v <= n); assert(1 <= c && c <= m); u--; v--; c--; if(u > v) { swap(u, v); } int lst_c = col[Edge(u, v)]; events[lst_c].emplace_back(ERASE, i, Edge(u, v)); col[Edge(u, v)] = c; events[c].emplace_back(INSERT, i, Edge(u, v)); } init(); for(int c = 0; c < m; c++) if(!events[c].empty()) { map timer; AINT aint(events[c].size()); for(int i = 0; i < (int) events[c].size(); i++) { Event ev = events[c][i]; if(ev.t == INSERT) { if(timer.count(ev.edge) == 0) { timer[ev.edge] = i; } } else { aint.update(timer[ev.edge], i - 1, ev.edge); timer.erase(ev.edge); } } for(const auto &it: timer) { aint.update(it.second, events[c].size(), it.first); } // dsu.init(); aint.solve(); int i = 0; if(events[c][i].time == 0) { while(i < (int) events[c].size() && events[c][i].time == 0) { i++; } res[c].emplace_back(0, ans[i - 1]); } else { res[c].emplace_back(0, 0); } while(i < (int) events[c].size()) { res[c].emplace_back(events[c][i].time, ans[i]); i++; } } int q; assert(fin >> q); assert(1 <= q && q <= kQ); for(int i = 0; i < q; i++) { int c, d; assert(fin >> c >> d); assert(1 <= c && c <= m); assert(1 <= d && d <= t); c--; if(res[c].empty()) { fout << "0\n"; } else { auto it = upper_bound(res[c].begin(), res[c].end(), make_pair(d, kInf)); it = prev(it); fout << it->second << '\n'; } } return 0; }