This submission is migrated from previous version of oj.uz, which used different machine for grading. This submission may have different result if resubmitted.
#include <bits/stdc++.h>
using namespace std;
#define all(x) begin(x), end(x)
#define sz(x) ((int)size(x))
#define trace(x) cout << #x << ": " << (x) << endl;
typedef long long ll;
const int N = 100000, M = 6000000;
int p[2][N];
int get(int a, int i) {
return (p[i][a] != a ? p[i][a] = get(p[i][a], i) : a);
}
bool same(int a, int b, int i) {
return get(a, i) == get(b, i);
}
bool mrg(int a, int b, int i) {
a = get(a, i), b = get(b, i);
if (a == b) return false;
p[i][b] = a;
return true;
}
vector<pair<int, int>> g[N];
//binary jumps with O(n) memory
//https://peltorator.ru/posts/linear_binups/
int jump[N], parent[N], depth[N], id_p[N];
int lca(int a, int b) {
if (depth[a] < depth[b]) swap(a, b);
while (depth[a] > depth[b]) {
if (depth[jump[a]] >= depth[b]) {
a = jump[a];
} else {
a = parent[a];
}
}
while (a != b) {
if (jump[a] != jump[b]) {
a = jump[a];
b = jump[b];
} else {
a = parent[a];
b = parent[b];
}
}
return a;
}
void add_leaf(int v, int par) {
assert(par != -1 && par != v);
parent[v] = par;
depth[v] = depth[par] + 1;
if (depth[par] - depth[jump[par]] == depth[jump[par]] - depth[jump[jump[par]]]) {
jump[v] = jump[jump[par]];
} else {
jump[v] = par;
}
}
int sz[N];
bool usedE[N];
//used edges
//d1 is just our tree, d2 is for merging in a path
void dfs(int v, int par, int id) {
add_leaf(v, par);
p[1][v] = v;
id_p[v] = id;
for (auto [to, i]: g[v]) {
if (to != par) {
dfs(to, v, i);
}
}
}
void union_path(int a, int b) {
int c = lca(a, b);
while (depth[a = get(a, 1)] > depth[c]) {
usedE[id_p[a]] = true;
mrg(parent[a], a, 1);
}
while (depth[b = get(b, 1)] > depth[c]) {
usedE[id_p[b]] = true;
mrg(parent[b], b, 1);
}
}
void merge(int a, int b, int idx) {
int pa = get(a, 0);
int pb = get(b, 0);
if (sz[pa] < sz[pb]) {
swap(a, b);
swap(pa, pb);
}
g[a].emplace_back(b, idx);
g[b].emplace_back(a, idx);
dfs(b, a, idx);
mrg(pa, pb, 0);
sz[pa] += sz[pb];
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
iota(jump, jump + N, 0);
iota(parent, parent + N, 0);
iota(p[0], p[0] + N, 0);
iota(p[1], p[1] + N, 0);
fill(sz, sz + N, 1);
int n, m;
cin >> n >> m;
int idx = 0;
for (int i = 0; i < m; ++i) {
int a, b;
cin >> a >> b;
--a, --b;
if (same(a, b, 0)) {
union_path(a, b);
} else {
merge(a, b, idx);
++idx;
}
}
for (int i = 0; i < n; ++i) {
for (auto [to, j] : g[i]) {
if (!usedE[j]) {
cout << i + 1 << " " << to + 1 << "\n";
usedE[j] = true;
}
}
}
return 0;
}
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |