Submission #468711

#TimeUsernameProblemLanguageResultExecution timeMemory
468711hoaphat1Unique Cities (JOI19_ho_t5)C++17
0 / 100
577 ms36880 KiB
#include <bits/stdc++.h> using namespace std; template <typename T> class graph { public: struct edge { int from; int to; T cost; }; vector<edge> edges; vector<vector<int>> g; int n; graph(int _n) : n(_n) { g.resize(n); } virtual int add(int from, int to, T cost) = 0; }; template <typename T> class forest : public graph<T> { public: using graph<T>::edges; using graph<T>::g; using graph<T>::n; forest(int _n) : graph<T>(_n) { } int add(int from, int to, T cost = 1) { assert(0 <= from && from < n && 0 <= to && to < n); int id = (int) edges.size(); assert(id < n - 1); g[from].push_back(id); g[to].push_back(id); edges.push_back({from, to, cost}); return id; } }; template <typename T> class dfs_forest : public forest<T> { public: using forest<T>::edges; using forest<T>::g; using forest<T>::n; vector<int> pv; vector<int> pe; vector<int> order; vector<int> pos; vector<int> end; vector<int> sz; vector<int> root; vector<int> depth; vector<T> dist; dfs_forest(int _n) : forest<T>(_n) { } void init() { pv = vector<int>(n, -1); pe = vector<int>(n, -1); order.clear(); pos = vector<int>(n, -1); end = vector<int>(n, -1); sz = vector<int>(n, 0); root = vector<int>(n, -1); depth = vector<int>(n, -1); dist = vector<T>(n); } void clear() { pv.clear(); pe.clear(); order.clear(); pos.clear(); end.clear(); sz.clear(); root.clear(); depth.clear(); dist.clear(); } private: void do_dfs(int v) { pos[v] = (int) order.size(); order.push_back(v); sz[v] = 1; for (int id : g[v]) { if (id == pe[v]) { continue; } auto &e = edges[id]; int to = e.from ^ e.to ^ v; depth[to] = depth[v] + 1; dist[to] = dist[v] + e.cost; pv[to] = v; pe[to] = id; root[to] = (root[v] != -1 ? root[v] : to); do_dfs(to); sz[v] += sz[to]; } end[v] = (int) order.size() - 1; } void do_dfs_from(int v) { depth[v] = 0; dist[v] = T{}; root[v] = v; pv[v] = pe[v] = -1; do_dfs(v); } public: void dfs(int v, bool clear_order = true) { if (pv.empty()) { init(); } else { if (clear_order) { order.clear(); } } do_dfs_from(v); } void dfs_all() { init(); for (int v = 0; v < n; v++) { if (depth[v] == -1) { do_dfs_from(v); } } assert((int) order.size() == n); } }; template <typename T> class lca_forest : public dfs_forest<T> { public: using dfs_forest<T>::edges; using dfs_forest<T>::g; using dfs_forest<T>::n; using dfs_forest<T>::pv; using dfs_forest<T>::pos; using dfs_forest<T>::end; using dfs_forest<T>::depth; int h; vector<vector<int>> pr; lca_forest(int _n) : dfs_forest<T>(_n) { } inline void build_lca() { assert(!pv.empty()); int max_depth = 0; for (int i = 0; i < n; i++) { max_depth = max(max_depth, depth[i]); } h = 1; while ((1 << h) <= max_depth) { h++; } pr.resize(n); for (int i = 0; i < n; i++) { pr[i].resize(h); pr[i][0] = pv[i]; } for (int j = 1; j < h; j++) { for (int i = 0; i < n; i++) { pr[i][j] = (pr[i][j - 1] == -1 ? -1 : pr[pr[i][j - 1]][j - 1]); } } } inline bool anc(int x, int y) { return (pos[x] <= pos[y] && end[y] <= end[x]); } inline int go_up(int x, int up) { assert(!pr.empty()); up = min(up, (1 << h) - 1); for (int j = h - 1; j >= 0; j--) { if (up & (1 << j)) { x = pr[x][j]; if (x == -1) { break; } } } return x; } inline int lca(int x, int y) { assert(!pr.empty()); if (anc(x, y)) { return x; } if (anc(y, x)) { return y; } for (int j = h - 1; j >= 0; j--) { if (pr[x][j] != -1 && !anc(pr[x][j], y)) { x = pr[x][j]; } } return pr[x][0]; } inline int length(int x, int y) { return depth[x] + depth[y] - 2 * depth[lca(x, y)]; } }; class segtree { public: struct node { // don't forget to set default value (used for leaves) // not necessarily neutral element! pair<int, int> val = {0, 0}; int put = 0; void apply(int l, int r, int v) { val.first += v; if (l != r) val.second += v; put += v; } }; node unite(const node &a, const node &b) const { node res; if (a.val.first > b.val.first) { res.val = make_pair(a.val.first, max(a.val.second, b.val.first)); } else { res.val = make_pair(b.val.first, max(a.val.first, b.val.second)); } return res; } inline void push(int x, int l, int r) { int y = (l + r) >> 1; int z = x + ((y - l + 1) << 1); if (tree[x].put != 0) { tree[x + 1].apply(l, y, tree[x].put); tree[z].apply(y + 1, r, tree[x].put); tree[x].put = 0; } } inline void pull(int x, int z) { tree[x] = unite(tree[x + 1], tree[z]); } int n; vector<node> tree; void build(int x, int l, int r) { if (l == r) { return; } int y = (l + r) >> 1; int z = x + ((y - l + 1) << 1); build(x + 1, l, y); build(z, y + 1, r); pull(x, z); } template <typename M> void build(int x, int l, int r, const vector<M> &v) { if (l == r) { tree[x].apply(l, r, v[l]); return; } int y = (l + r) >> 1; int z = x + ((y - l + 1) << 1); build(x + 1, l, y, v); build(z, y + 1, r, v); pull(x, z); } node get(int x, int l, int r, int ll, int rr) { if (ll <= l && r <= rr) { return tree[x]; } int y = (l + r) >> 1; int z = x + ((y - l + 1) << 1); push(x, l, r); node res{}; if (rr <= y) { res = get(x + 1, l, y, ll, rr); } else { if (ll > y) { res = get(z, y + 1, r, ll, rr); } else { res = unite(get(x + 1, l, y, ll, rr), get(z, y + 1, r, ll, rr)); } } pull(x, z); return res; } template <typename... M> void modify(int x, int l, int r, int ll, int rr, const M&... v) { if (ll <= l && r <= rr) { tree[x].apply(l, r, v...); return; } int y = (l + r) >> 1; int z = x + ((y - l + 1) << 1); push(x, l, r); if (ll <= y) { modify(x + 1, l, y, ll, rr, v...); } if (rr > y) { modify(z, y + 1, r, ll, rr, v...); } pull(x, z); } int find_first_knowingly(int x, int l, int r, const function<bool(const node&)> &f) { if (l == r) { return l; } push(x, l, r); int y = (l + r) >> 1; int z = x + ((y - l + 1) << 1); int res; if (f(tree[x + 1])) { res = find_first_knowingly(x + 1, l, y, f); } else { res = find_first_knowingly(z, y + 1, r, f); } pull(x, z); return res; } int find_first(int x, int l, int r, int ll, int rr, const function<bool(const node&)> &f) { if (ll <= l && r <= rr) { if (!f(tree[x])) { return -1; } return find_first_knowingly(x, l, r, f); } push(x, l, r); int y = (l + r) >> 1; int z = x + ((y - l + 1) << 1); int res = -1; if (ll <= y) { res = find_first(x + 1, l, y, ll, rr, f); } if (rr > y && res == -1) { res = find_first(z, y + 1, r, ll, rr, f); } pull(x, z); return res; } int find_last_knowingly(int x, int l, int r, const function<bool(const node&)> &f) { if (l == r) { return l; } push(x, l, r); int y = (l + r) >> 1; int z = x + ((y - l + 1) << 1); int res; if (f(tree[z])) { res = find_last_knowingly(z, y + 1, r, f); } else { res = find_last_knowingly(x + 1, l, y, f); } pull(x, z); return res; } int find_last(int x, int l, int r, int ll, int rr, const function<bool(const node&)> &f) { if (ll <= l && r <= rr) { if (!f(tree[x])) { return -1; } return find_last_knowingly(x, l, r, f); } push(x, l, r); int y = (l + r) >> 1; int z = x + ((y - l + 1) << 1); int res = -1; if (rr > y) { res = find_last(z, y + 1, r, ll, rr, f); } if (ll <= y && res == -1) { res = find_last(x + 1, l, y, ll, rr, f); } pull(x, z); return res; } segtree(int _n) : n(_n) { assert(n > 0); tree.resize(2 * n - 1); build(0, 0, n - 1); } template <typename M> segtree(const vector<M> &v) { n = v.size(); assert(n > 0); tree.resize(2 * n - 1); build(0, 0, n - 1, v); } node get(int ll, int rr) { assert(0 <= ll && ll <= rr && rr <= n - 1); return get(0, 0, n - 1, ll, rr); } node get(int p) { assert(0 <= p && p <= n - 1); return get(0, 0, n - 1, p, p); } template <typename... M> void modify(int ll, int rr, const M&... v) { assert(0 <= ll && ll <= rr && rr <= n - 1); modify(0, 0, n - 1, ll, rr, v...); } // find_first and find_last call all FALSE elements // to the left (right) of the sought position exactly once int find_first(int ll, int rr, const function<bool(const node&)> &f) { assert(0 <= ll && ll <= rr && rr <= n - 1); return find_first(0, 0, n - 1, ll, rr, f); } int find_last(int ll, int rr, const function<bool(const node&)> &f) { assert(0 <= ll && ll <= rr && rr <= n - 1); return find_last(0, 0, n - 1, ll, rr, f); } }; /// template from tourist #include<ext/pb_ds/assoc_container.hpp> using namespace __gnu_pbds; template<typename T> using order_set = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>; int main() { ios::sync_with_stdio(false); cin.tie(0); int n, m; cin >> n >> m; lca_forest<int> g(n); for (int i = 1; i < n; i++) { int u, v; cin >> u >> v; --u; --v; g.add(u, v); } g.dfs(0); vector<int> dia(2); dia[0] = max_element(g.depth.begin(), g.depth.end()) - g.depth.begin(); g.dfs(dia[0]); dia[1] = max_element(g.depth.begin(), g.depth.end()) - g.depth.begin(); g.build_lca(); vector<int> c(n); for (int i = 0; i < n; i++) { cin >> c[i]; --c[i]; } vector<order_set<int>> s(2); for (int i = 0; i < 2; i++) { vector<vector<int>> belong(n); function<void(int, int, int)> dfs = [&](int v, int p, int depth) { belong[depth].push_back(v); for (int id: g.g[v]) { auto& e = g.edges[id]; int u = e.from ^ e.to ^ v; if (u == p) continue; dfs(u, v, depth + 1); } }; dfs(dia[i], -1, 0); vector<bool> kt(m); for (int j = 0; j < n; j++) { if ((int) belong[j].size() != 1) continue; for (auto&v : belong[j]) { if (!kt[c[v]]) { kt[c[v]] = true; s[i].insert(j); } else if (c[dia[i]] == c[v]) s[i].insert(n); } } } segtree Tree(n); for (int i = 0; i < n; i++) Tree.modify(g.pos[i], g.pos[i], g.depth[i]); vector<pair<int, int>> d(n); function<void(int, int)> dfs = [&](int v, int p) { d[v] = Tree.get(0, Tree.n - 1).val; for (int id: g.g[v]) { auto& e = g.edges[id]; int u = e.from ^ e.to ^ v; if (u == p) continue; Tree.modify(0, Tree.n - 1, 1); Tree.modify(g.pos[u], g.end[u], -2); dfs(u, v); Tree.modify(0, Tree.n - 1, -1); Tree.modify(g.pos[u], g.end[u], 2); } }; dfs(dia[0], -1); for (int i = 0; i < n; i++) { bool flag = false; for (int j = 0; j < 2; j++) { if (i == dia[j]) { cout << (int) s[j].size() - 1 << "\n"; flag = true; break; } } if (flag) continue; int res = 0; int d1 = g.length(dia[0], i); int d2 = g.length(dia[1], i); if (d2 > d1) { swap(d1, d2); res = 1; } assert(d1 == d[i].first); cout << s[res].order_of_key(d1 - d[i].second) << "\n"; } }
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...