2023 rcpc
This commit is contained in:
383
2023/rcpc/d2/editorial/f-suceava-537.cpp
Normal file
383
2023/rcpc/d2/editorial/f-suceava-537.cpp
Normal file
@@ -0,0 +1,383 @@
|
||||
#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;
|
||||
}
|
||||
Reference in New Issue
Block a user