-
Notifications
You must be signed in to change notification settings - Fork 2
/
Find bridges (online).cpp
114 lines (104 loc) · 2.3 KB
/
Find bridges (online).cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
// O((n+m)*log(n))
struct BridgeFinder {
// 2ecc = 2 edge conected component
// cc = conected component
vector<int> parent, dsu_2ecc, dsu_cc,
dsu_cc_size;
int bridges, lca_iteration;
vector<int> last_visit;
BridgeFinder(int n)
: parent(n, -1),
dsu_2ecc(n),
dsu_cc(n),
dsu_cc_size(n, 1),
bridges(0),
lca_iteration(0),
last_visit(n) {
for (int i = 0; i < n; i++) {
dsu_2ecc[i] = i;
dsu_cc[i] = i;
}
}
int find_2ecc(int v) {
if (v == -1) return -1;
return dsu_2ecc[v] == v
? v
: dsu_2ecc[v] =
find_2ecc(dsu_2ecc[v]);
}
int find_cc(int v) {
v = find_2ecc(v);
return dsu_cc[v] == v
? v
: dsu_cc[v] = find_cc(dsu_cc[v]);
}
void make_root(int v) {
v = find_2ecc(v);
int root = v;
int child = -1;
while (v != -1) {
int p = find_2ecc(parent[v]);
parent[v] = child;
dsu_cc[v] = root;
child = v;
v = p;
}
dsu_cc_size[root] = dsu_cc_size[child];
}
void merge_path(int a, int b) {
++lca_iteration;
vector<int> path_a, path_b;
int lca = -1;
while (lca == -1) {
if (a != -1) {
a = find_2ecc(a);
path_a.push_back(a);
if (last_visit[a] == lca_iteration) {
lca = a;
break;
}
last_visit[a] = lca_iteration;
a = parent[a];
}
if (b != -1) {
b = find_2ecc(b);
path_b.push_back(b);
if (last_visit[b] == lca_iteration) {
lca = b;
break;
}
last_visit[b] = lca_iteration;
b = parent[b];
}
}
for (auto v : path_a) {
dsu_2ecc[v] = lca;
if (v == lca) break;
--bridges;
}
for (auto v : path_b) {
dsu_2ecc[v] = lca;
if (v == lca) break;
--bridges;
}
}
void add_edge(int a, int b) {
a = find_2ecc(a);
b = find_2ecc(b);
if (a == b) return;
int ca = find_cc(a);
int cb = find_cc(b);
if (ca != cb) {
++bridges;
if (dsu_cc_size[ca] > dsu_cc_size[cb]) {
swap(a, b);
swap(ca, cb);
}
make_root(a);
parent[a] = dsu_cc[a] = b;
dsu_cc_size[cb] += dsu_cc_size[a];
} else {
merge_path(a, b);
}
}
};