384 lines
6.6 KiB
C++
384 lines
6.6 KiB
C++
#include <bits/stdc++.h>
|
|
|
|
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<int> 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<Edge, int> col;
|
|
|
|
struct Event {
|
|
bool t;
|
|
int time;
|
|
Edge edge;
|
|
Event(bool t, int time, Edge edge): t(t), time(time), edge(edge) {}
|
|
};
|
|
|
|
vector<Event> events[kN];
|
|
vector<pair<int, int>> res[kN];
|
|
|
|
struct DSU {
|
|
struct DSU_SAVE {
|
|
int u, v;
|
|
pair<int, int> diameter;
|
|
DSU_SAVE() {}
|
|
DSU_SAVE(int u, int v, pair<int, int> diameter): u(u), v(v), diameter(diameter) {}
|
|
};
|
|
|
|
int n;
|
|
vector<int> par, sz;
|
|
vector<pair<int, int>> diameter;
|
|
stack<DSU_SAVE> 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<int, int> findDiameter(int u) {
|
|
return diameter[findRoot(u)];
|
|
}
|
|
|
|
pair<int, int> join(int u, int v) {
|
|
pair<int, int> t1 = findDiameter(u);
|
|
pair<int, int> t2 = findDiameter(v);
|
|
|
|
vector<pair<int, int>> candidates = {
|
|
t1,
|
|
t2,
|
|
{t1.first, t2.first},
|
|
{t1.first, t2.second},
|
|
{t1.second, t2.first},
|
|
{t1.second, t2.second}
|
|
};
|
|
|
|
int max_dist = 0;
|
|
pair<int, int> 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<int, int> 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<int> ans;
|
|
|
|
struct AINT {
|
|
int n;
|
|
vector<vector<Edge>> 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<int>(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<Edge, int> 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;
|
|
}
|