This documentation is automatically generated by online-judge-tools/verification-helper
#include <clocale>
#define PROBLEM "https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2235"
#include "../disjoint_set/rollback_disjoint_set.hpp"
#include "../graph/offline_dynamic_connectivity.hpp"
#include <bits/stdc++.h>
int main() {
std::cin.tie(0)->sync_with_stdio(0);
int n, k;
std::cin >> n >> k;
offline_dynamic_connectivity<rollback_disjoint_set> dc(n);
std::vector<std::pair<int, int>> q;
dc.reserve(k);
q.reserve(k);
while (k--) {
int t, u, v;
std::cin >> t >> u >> v;
switch (t) {
case 1:
case 2:
dc.toggle_edge(u, v);
break;
case 3:
q.emplace_back(u, v);
dc.snapshot();
break;
}
}
auto result = dc.solve([&](const auto &dsu, int i) {
auto [u, v] = q[i];
return dsu.same(u, v);
});
for (auto b : result) {
std::cout << (b ? "YES\n" : "NO\n");
}
}
#line 1 "test/offline_dynamic_connectivity.test.cpp"
#include <clocale>
#define PROBLEM "https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2235"
#line 1 "disjoint_set/rollback_disjoint_set.hpp"
#include <cassert>
#include <stack>
#include <utility>
#include <vector>
struct rollback_disjoint_set {
explicit rollback_disjoint_set(int n) : n_(n), parent_or_size_(n, -1) {}
int find(int u) const {
return parent_or_size_[u] < 0 ? u : find(parent_or_size_[u]);
}
bool merge(int u, int v) {
assert(0 <= u && u < n_ && 0 <= v && v < n_);
u = find(u);
v = find(v);
if (u == v) {
return false;
}
if (-parent_or_size_[u] < -parent_or_size_[v]) {
std::swap(u, v);
}
history_.emplace(v, parent_or_size_[v]);
parent_or_size_[u] += parent_or_size_[v];
parent_or_size_[v] = u;
return true;
}
bool same(int u, int v) const {
assert(0 <= u && u < n_ && 0 <= v && v < n_);
return find(u) == find(v);
}
int size(int u) const {
assert(0 <= u && u < n_);
return -parent_or_size_[find(u)];
}
void rollback() {
assert(!history_.empty());
auto [v, val] = history_.top();
auto u = parent_or_size_[v];
parent_or_size_[v] = val;
parent_or_size_[u] -= val;
history_.pop();
}
void rollback(int count) {
for (auto i = 0; i < count; ++i) {
rollback();
}
}
private:
int n_;
std::vector<int> parent_or_size_;
std::stack<std::pair<int, int>> history_;
};
#line 1 "graph/offline_dynamic_connectivity.hpp"
#include <algorithm>
#include <array>
#line 7 "graph/offline_dynamic_connectivity.hpp"
#include <type_traits>
#line 10 "graph/offline_dynamic_connectivity.hpp"
template <typename DisjointSet> struct offline_dynamic_connectivity {
explicit offline_dynamic_connectivity(int n) : n_(n), timer_(0) {}
void toggle_edge(int u, int v) {
assert(0 <= u && u < n_ && 0 <= v && v < n_);
if (u > v) {
std::swap(u, v);
}
edges_.push_back({u, v, timer_});
}
int snapshot() { return timer_++; }
void reserve(int n) { edges_.reserve(n); }
template <typename Function>
std::vector<std::invoke_result_t<Function, DisjointSet, int>>
solve(Function f) {
auto k = timer_;
if (k == 0) {
return {};
}
std::sort(edges_.begin(), edges_.end());
std::vector<std::vector<std::pair<int, int>>> segment(2 * k);
auto edges_size = static_cast<int>(edges_.size());
for (auto i = 0; i < edges_size; ++i) {
auto [u, v, l] = edges_[i];
auto r = k;
if (i + 1 < edges_size && u == edges_[i + 1][0] &&
v == edges_[i + 1][1]) {
r = edges_[++i][2];
}
l += k;
r += k;
while (l < r) {
if (l & 1) {
segment[l++].push_back({u, v});
}
if (r & 1) {
segment[--r].push_back({u, v});
}
l >>= 1;
r >>= 1;
}
}
DisjointSet dsu(n_);
std::vector<std::invoke_result_t<Function, DisjointSet, int>> result(k);
auto dfs = [&](auto self, int node) -> void {
auto count = 0;
for (auto [u, v] : segment[node]) {
if (dsu.merge(u, v)) {
++count;
}
}
if (node < k) {
self(self, 2 * node);
self(self, 2 * node + 1);
} else {
result[node - k] = f(dsu, node - k);
}
dsu.rollback(count);
};
dfs(dfs, 1);
return result;
}
private:
int n_, timer_;
std::vector<std::array<int, 3>> edges_;
};
#line 6 "test/offline_dynamic_connectivity.test.cpp"
#include <bits/stdc++.h>
int main() {
std::cin.tie(0)->sync_with_stdio(0);
int n, k;
std::cin >> n >> k;
offline_dynamic_connectivity<rollback_disjoint_set> dc(n);
std::vector<std::pair<int, int>> q;
dc.reserve(k);
q.reserve(k);
while (k--) {
int t, u, v;
std::cin >> t >> u >> v;
switch (t) {
case 1:
case 2:
dc.toggle_edge(u, v);
break;
case 3:
q.emplace_back(u, v);
dc.snapshot();
break;
}
}
auto result = dc.solve([&](const auto &dsu, int i) {
auto [u, v] = q[i];
return dsu.same(u, v);
});
for (auto b : result) {
std::cout << (b ? "YES\n" : "NO\n");
}
}