Files
contests/2023/rcpc/d2/editorial/f-suceava-537.cpp
2024-04-22 16:45:09 +03:00

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;
}