#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;
struct dsu {
int p[N];
dsu() = default;
dsu(int n) {
iota(p, p + n, 0);
}
void init(int n) {
iota(p, p + n, 0);
}
int get(int a) {
int x = a;
while (p[a] != a) {
a = p[a];
}
while (x != a) {
int v = p[x];
p[x] = a;
x = v;
}
return a;
}
bool same(int a, int b) {
return get(a) == get(b);
}
bool mrg(int a, int b) {
a = get(a), b = get(b);
if (a == b) return false;
p[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 A[N], B[N], sz[N];
bool usedE[N];
//used edges
dsu d1, d2;
//d1 is just our tree, d2 is for merging in a path
void dfs(int v, int par, int id) {
add_leaf(v, par);
d2.p[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 = d2.get(a)] > depth[c]) {
usedE[id_p[a]] = true;
d2.mrg(parent[a], a);
}
while (depth[b = d2.get(b)] > depth[c]) {
usedE[id_p[b]] = true;
d2.mrg(parent[b], b);
}
}
void merge(int a, int b, int idx) {
int pa = d1.get(a);
int pb = d1.get(b);
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);
d1.mrg(pa, pb);
sz[pa] += sz[pb];
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
iota(jump, jump + N, 0);
iota(parent, parent + N, 0);
int n, m;
cin >> n >> m;
d1.init(n);
d2.init(n);
int idx = 0;
for (int i = 0; i < m; ++i) {
int a, b;
cin >> a >> b;
--a, --b;
if (d1.same(a, b)) {
union_path(a, b);
} else {
A[idx] = a, B[idx] = b;
merge(a, b, idx);
++idx;
}
}
for (int i = 0; i < idx; ++i) {
if (!usedE[i]) {
cout << A[i] + 1 << " " << B[i] + 1 << '\n';
}
}
return 0;
}
# |
결과 |
실행 시간 |
메모리 |
Grader output |
1 |
Correct |
2 ms |
3412 KB |
Output is correct |
2 |
Correct |
2 ms |
3412 KB |
Output is correct |
# |
결과 |
실행 시간 |
메모리 |
Grader output |
1 |
Correct |
64 ms |
3732 KB |
Output is correct |
2 |
Correct |
27 ms |
3668 KB |
Output is correct |
# |
결과 |
실행 시간 |
메모리 |
Grader output |
1 |
Correct |
156 ms |
3668 KB |
Output is correct |
2 |
Correct |
125 ms |
3688 KB |
Output is correct |
# |
결과 |
실행 시간 |
메모리 |
Grader output |
1 |
Correct |
576 ms |
4096 KB |
Output is correct |
2 |
Correct |
320 ms |
4116 KB |
Output is correct |
# |
결과 |
실행 시간 |
메모리 |
Grader output |
1 |
Correct |
2994 ms |
5088 KB |
Output is correct |
2 |
Runtime error |
1895 ms |
19116 KB |
Memory limit exceeded |
3 |
Halted |
0 ms |
0 KB |
- |
# |
결과 |
실행 시간 |
메모리 |
Grader output |
1 |
Execution timed out |
5067 ms |
7340 KB |
Time limit exceeded |
2 |
Halted |
0 ms |
0 KB |
- |
# |
결과 |
실행 시간 |
메모리 |
Grader output |
1 |
Execution timed out |
5066 ms |
7880 KB |
Time limit exceeded |
2 |
Halted |
0 ms |
0 KB |
- |
# |
결과 |
실행 시간 |
메모리 |
Grader output |
1 |
Execution timed out |
5092 ms |
8608 KB |
Time limit exceeded |
2 |
Halted |
0 ms |
0 KB |
- |
# |
결과 |
실행 시간 |
메모리 |
Grader output |
1 |
Execution timed out |
5078 ms |
8676 KB |
Time limit exceeded |
2 |
Halted |
0 ms |
0 KB |
- |
# |
결과 |
실행 시간 |
메모리 |
Grader output |
1 |
Execution timed out |
5066 ms |
8272 KB |
Time limit exceeded |
2 |
Halted |
0 ms |
0 KB |
- |