-
Notifications
You must be signed in to change notification settings - Fork 16
/
functional-graph.hpp
127 lines (111 loc) · 3.13 KB
/
functional-graph.hpp
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
115
116
117
118
119
120
121
122
123
124
125
126
127
#pragma once
#include <cassert>
#include <utility>
#include <vector>
using namespace std;
#include "../data-structure/union-find.hpp"
#include "../internal/internal-type-traits.hpp"
#include "graph-template.hpp"
namespace FunctionalGraphImpl {
ENABLE_HAS_VAR(cost)
template <typename T = int>
struct FunctionalGraph {
int N;
WeightedGraph<T> g;
vector<int> to, represent;
vector<T> weight;
FunctionalGraph() = default;
FunctionalGraph(int n, const vector<int>& adj,
const vector<T>& w = vector<int>{})
: N(n), g(N + 1), to(N + 1, -1), represent(N + 1, -1), weight(N + 1) {
assert((int)adj.size() == N);
assert((int)w.size() == N or w.empty());
for (auto& x : adj) assert(0 <= x and x < N);
UnionFind uf(N);
for (int i = 0; i < N; i++) {
int j = adj[i];
to[i] = j, weight[i] = w.empty() ? T{1} : w[i];
if (uf.same(i, j)) {
g[N].emplace_back(N, i, weight[i]);
} else {
uf.unite(i, j);
g[j].emplace_back(j, i, weight[i]);
}
}
calc_represent(N, -1);
}
// _g は無向グラフ
template <typename G>
FunctionalGraph(int n, const G& _g)
: N(n), g(N + 1), to(N + 1, -1), represent(N + 1, -1), weight(N + 1) {
constexpr bool cost_flag = has_cost_v<typename G::value_type::value_type>;
WeightedGraph<T> h(n);
UnionFind uf(N);
for (int i = 0; i < N; i++) {
for (auto& j : _g[i]) {
if (i > j) continue;
T cost;
if constexpr (cost_flag) {
cost = j.cost;
} else {
cost = 1;
}
if (uf.same(i, j)) {
// i -> j 向きということにして, i を根とする
g[N].emplace_back(N, i, 0);
to[i] = j, weight[i] = cost;
} else {
uf.unite(i, j);
h[i].emplace_back(i, j, cost);
h[j].emplace_back(j, i, cost);
}
}
}
auto dfs = [&](auto rc, int c, int p) -> void {
for (auto& d : h[c]) {
if (d == p) continue;
T cost;
if constexpr (cost_flag) {
cost = d.cost;
} else {
cost = 1;
}
to[d] = c, weight[d] = cost;
g[c].emplace_back(c, d, cost);
rc(rc, d, c);
}
};
for (auto& r : g[N]) dfs(dfs, r, -1);
calc_represent(N, -1);
}
vector<vector<int>> get_loops() const {
vector<vector<int>> res;
for (auto r : g[N]) {
vector<int> cur{r};
for (int i = to[r]; i != r; i = to[i]) {
cur.push_back(i);
}
res.push_back(cur);
}
return res;
}
// (u, {weight of u-v}) (v, {weight of v-w}), (w, ...) ...
vector<vector<pair<int, T>>> get_loops_with_weight() const {
vector<vector<pair<int, T>>> res;
for (auto r : g[N]) {
vector<pair<int, T>> cur{make_pair(r, weight[r])};
for (int i = to[r]; i != r; i = to[i]) {
cur.emplace_back(i, weight[i]);
}
res.push_back(cur);
}
return res;
}
private:
void calc_represent(int c, int r) {
represent[c] = r;
for (auto& d : g[c]) calc_represent(d, r == -1 ? d : r);
}
};
} // namespace FunctionalGraphImpl
using FunctionalGraphImpl::FunctionalGraph;