This documentation is automatically generated by online-judge-tools/verification-helper
View the Project on GitHub hitonanode/cplib-cpp
#define PROBLEM "https://judge.yosupo.jp/problem/dynamic_graph_vertex_add_component_sum" #include "../../unionfind/undo_monoid_unionfind.hpp" #include "../offline_dynamic_connectivity.hpp" #include <iostream> #include <map> #include <utility> using namespace std; int main() { cin.tie(nullptr), ios::sync_with_stdio(false); int N, Q; cin >> N >> Q; using lint = long long; vector<lint> a(N); for (auto &x : a) cin >> x; vector<pair<int, int>> edges; map<pair<int, int>, pair<int, int>> edge_to_id_since; offline_dynamic_connectivity<std::pair<int, int>> dc; // for verification vector<pair<int, lint>> qs; vector<int> get_query; vector<lint> ret; for (int q = 0; q < Q; ++q) { int tp; cin >> tp; if (tp <= 1) { int u, v; cin >> u >> v; if (u > v) swap(u, v); if (tp == 0) { edge_to_id_since[make_pair(u, v)] = make_pair(edges.size(), q); edges.emplace_back(u, v); } else { int id_, since; tie(id_, since) = edge_to_id_since[make_pair(u, v)]; dc.apply_time_range({since, 0}, {q, 0}, id_); edge_to_id_since.erase(make_pair(u, v)); } } else if (tp == 2) { int v; lint x; cin >> v >> x; dc.apply_time_range({q, 0}, {1 << 30, 0}, -1 - int(qs.size())); qs.emplace_back(v, x); } else if (tp == 3) { int v; cin >> v; dc.add_observation({q, 0}, ret.size()); get_query.push_back(v); ret.push_back(0); } } for (auto p : edge_to_id_since) { dc.apply_time_range({p.second.second, 0}, {1 << 30, 0}, p.second.first); } undo_dsu<lint> dsu(a); for (auto p : dc.generate()) { if (p.op == DyConOperation::Begins) { if (p.id_ >= 0) { auto edge = edges.at(p.id_); dsu.unite(edge.first, edge.second); } else { auto q = qs.at(-p.id_ - 1); int v = q.first, x = q.second; dsu.set_weight(v, dsu.sum(v) + x); } } else if (p.op == DyConOperation::Ends) { dsu.undo(); } else if (p.op == DyConOperation::Event) { int v = get_query.at(p.id_); ret.at(p.id_) = dsu.sum(v); } } for (auto x : ret) cout << x << '\n'; }
#line 1 "data_structure/test/dynamic_graph_vertex_add_component_sum.test.cpp" #define PROBLEM "https://judge.yosupo.jp/problem/dynamic_graph_vertex_add_component_sum" #line 2 "unionfind/undo_monoid_unionfind.hpp" #include <numeric> #include <tuple> #include <utility> #include <vector> // UnionFind, able to rewind to the previous state by undo() template <class S> struct undo_dsu { std::vector<int> par, cou; std::vector<S> weights; std::vector<std::tuple<int, int, S>> history; explicit undo_dsu(const std::vector<S> &init) : par(init.size()), cou(init.size(), 1), weights(init) { std::iota(par.begin(), par.end(), 0); } explicit undo_dsu(int N) : undo_dsu(std::vector<S>(N, S())) {} undo_dsu() : undo_dsu(0) {} int find(int x) const { return (par[x] == x) ? x : find(par[x]); } bool unite(int x, int y) { x = find(x), y = find(y); if (cou[x] < cou[y]) std::swap(x, y); history.emplace_back(y, cou[x], weights[x]); return x != y ? par[y] = x, cou[x] += cou[y], weights[x] += weights[y], true : false; } void set_weight(int x, S w) { x = find(x); history.emplace_back(x, cou[x], weights[x]); weights[x] = w; } void undo() { weights[par[std::get<0>(history.back())]] = std::get<2>(history.back()); cou[par[std::get<0>(history.back())]] = std::get<1>(history.back()); par[std::get<0>(history.back())] = std::get<0>(history.back()); history.pop_back(); } void reset() { while (!history.empty()) undo(); } int count(int x) const { return cou[find(x)]; } const S &sum(int x) const { return weights[find(x)]; } bool same(int x, int y) const { return find(x) == find(y); } }; #line 2 "data_structure/offline_dynamic_connectivity.hpp" #include <algorithm> #include <limits> #include <set> #line 7 "data_structure/offline_dynamic_connectivity.hpp" enum class DyConOperation { Begins = 1, Ends = 2, Event = 3, }; template <class Tick = int> struct offline_dynamic_connectivity { std::vector<std::pair<Tick, int>> ops; struct Edge { Tick since; Tick until; int edge_id; }; std::vector<Edge> edges; offline_dynamic_connectivity() = default; void add_observation(Tick clk, int event_id) { ops.emplace_back(clk, event_id); } void apply_time_range(Tick since, Tick until, int edge_id) { edges.push_back(Edge{since, until, edge_id}); } struct Procedure { DyConOperation op; int id_; }; std::vector<std::vector<Procedure>> nodes; std::vector<Procedure> ret_; void rec(int now) { ret_.insert(ret_.end(), nodes[now].cbegin(), nodes[now].cend()); if (now * 2 < int(nodes.size())) rec(now * 2); if (now * 2 + 1 < int(nodes.size())) rec(now * 2 + 1); for (auto itr = nodes[now].rbegin(); itr != nodes[now].rend(); ++itr) { if (itr->op == DyConOperation::Begins) { ret_.push_back(Procedure{DyConOperation::Ends, itr->id_}); } } } std::vector<Procedure> generate() { if (ops.empty()) return {}; std::vector<Tick> query_ts; { query_ts.reserve(ops.size()); for (const auto &p : ops) query_ts.push_back(p.first); std::sort(query_ts.begin(), query_ts.end()); query_ts.erase(std::unique(query_ts.begin(), query_ts.end()), query_ts.end()); std::vector<int> t_use(query_ts.size() + 1); t_use.at(0) = 1; for (const Edge &e : edges) { t_use[std::lower_bound(query_ts.begin(), query_ts.end(), e.since) - query_ts.begin()] = 1; t_use[std::lower_bound(query_ts.begin(), query_ts.end(), e.until) - query_ts.begin()] = 1; } for (int i = 1; i < int(query_ts.size()); ++i) { if (!t_use[i]) query_ts[i] = query_ts[i - 1]; } query_ts.erase(std::unique(query_ts.begin(), query_ts.end()), query_ts.end()); } const int N = query_ts.size(); int D = 1; while (D < int(query_ts.size())) D *= 2; nodes.assign(D + N, {}); for (const Edge &e : edges) { int l = D + (std::lower_bound(query_ts.begin(), query_ts.end(), e.since) - query_ts.begin()); int r = D + (std::lower_bound(query_ts.begin(), query_ts.end(), e.until) - query_ts.begin()); while (l < r) { if (l & 1) nodes[l++].push_back(Procedure{DyConOperation::Begins, e.edge_id}); if (r & 1) nodes[--r].push_back(Procedure{DyConOperation::Begins, e.edge_id}); l >>= 1, r >>= 1; } } for (const auto &op : ops) { int t = std::upper_bound(query_ts.begin(), query_ts.end(), op.first) - query_ts.begin(); nodes.at(t + D - 1).push_back(Procedure{DyConOperation::Event, op.second}); } ret_.clear(); rec(1); return ret_; } }; #line 4 "data_structure/test/dynamic_graph_vertex_add_component_sum.test.cpp" #include <iostream> #include <map> #line 8 "data_structure/test/dynamic_graph_vertex_add_component_sum.test.cpp" using namespace std; int main() { cin.tie(nullptr), ios::sync_with_stdio(false); int N, Q; cin >> N >> Q; using lint = long long; vector<lint> a(N); for (auto &x : a) cin >> x; vector<pair<int, int>> edges; map<pair<int, int>, pair<int, int>> edge_to_id_since; offline_dynamic_connectivity<std::pair<int, int>> dc; // for verification vector<pair<int, lint>> qs; vector<int> get_query; vector<lint> ret; for (int q = 0; q < Q; ++q) { int tp; cin >> tp; if (tp <= 1) { int u, v; cin >> u >> v; if (u > v) swap(u, v); if (tp == 0) { edge_to_id_since[make_pair(u, v)] = make_pair(edges.size(), q); edges.emplace_back(u, v); } else { int id_, since; tie(id_, since) = edge_to_id_since[make_pair(u, v)]; dc.apply_time_range({since, 0}, {q, 0}, id_); edge_to_id_since.erase(make_pair(u, v)); } } else if (tp == 2) { int v; lint x; cin >> v >> x; dc.apply_time_range({q, 0}, {1 << 30, 0}, -1 - int(qs.size())); qs.emplace_back(v, x); } else if (tp == 3) { int v; cin >> v; dc.add_observation({q, 0}, ret.size()); get_query.push_back(v); ret.push_back(0); } } for (auto p : edge_to_id_since) { dc.apply_time_range({p.second.second, 0}, {1 << 30, 0}, p.second.first); } undo_dsu<lint> dsu(a); for (auto p : dc.generate()) { if (p.op == DyConOperation::Begins) { if (p.id_ >= 0) { auto edge = edges.at(p.id_); dsu.unite(edge.first, edge.second); } else { auto q = qs.at(-p.id_ - 1); int v = q.first, x = q.second; dsu.set_weight(v, dsu.sum(v) + x); } } else if (p.op == DyConOperation::Ends) { dsu.undo(); } else if (p.op == DyConOperation::Event) { int v = get_query.at(p.id_); ret.at(p.id_) = dsu.sum(v); } } for (auto x : ret) cout << x << '\n'; }