Skip to content

Commit

Permalink
condense
Browse files Browse the repository at this point in the history
  • Loading branch information
lrvideckis committed Nov 27, 2024
1 parent 23f3219 commit 15f5bd3
Showing 1 changed file with 24 additions and 214 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,152 +3,14 @@
#include "../template.hpp"
#include "../../../library/contest/random.hpp"
#include "../../../library/graphs/functional_graph_processor.hpp"
template<class T> struct graph {
using Weight_t = T;
struct Edge_t {
int from, to;
T cost;
Edge_t &inplace_flip() {
swap(from, to);
return *this;
}
Edge_t flip() const { return (*this).inplace_flip(); }
};
int n;
vector<Edge_t> edge;
vector<vector<int>> adj;
function<bool(int)> ignore;
graph(int n = 1): n(n), adj(n) { assert(n >= 1); }
graph(const vector<vector<int>> &adj,
bool undirected = true): n((int)adj.size()), adj(n) {
assert(n >= 1);
if (undirected) {
for (auto u = 0; u < n; ++u)
for (auto v : adj[u])
if (u < v) link(u, v);
} else
for (auto u = 0; u < n; ++u)
for (auto v : adj[u]) orient(u, v);
}
graph(const vector<vector<pair<int, T>>> &adj,
bool undirected = true): n((int)adj.size()), adj(n) {
assert(n >= 1);
if (undirected) {
for (auto u = 0; u < n; ++u)
for (auto [v, w] : adj[u])
if (u < v) link(u, v, w);
} else
for (auto u = 0; u < n; ++u)
for (auto [v, w] : adj[u]) orient(u, v, w);
}
graph(int n, vector<array<int, 2>> &edge,
bool undirected = true): n(n), adj(n) {
assert(n >= 1);
for (auto [u, v] : edge)
undirected ? link(u, v) : orient(u, v);
}
graph(int n, vector<tuple<int, int, T>> &edge,
bool undirected = true): n(n), adj(n) {
assert(n >= 1);
for (auto [u, v, w] : edge)
undirected ? link(u, v, w) : orient(u, v, w);
}
int add_vertex() {
adj.emplace_back();
return n++;
}
int operator()(int u, int id) const {
#ifdef LOCAL
assert(0 <= id && id < (int)edge.size());
assert(edge[id].from == u || edge[id].to == u);
#endif
return u ^ edge[id].from ^ edge[id].to;
}
int link(int u, int v,
T w = {}) { // insert an undirected edge
int id = (int)edge.size();
adj[u].push_back(id), adj[v].push_back(id),
edge.push_back({u, v, w});
return id;
}
int orient(int u, int v,
T w = {}) { // insert a directed edge
int id = (int)edge.size();
adj[u].push_back(id), edge.push_back({u, v, w});
return id;
}
vector<int> neighbor(int u, int exclude = -1) const {
vector<int> res;
for (auto id : adj[u]) {
if (id == exclude || ignore && ignore(id)) continue;
res.push_back(operator()(u, id));
}
return res;
}
vector<array<int, 2>> weighted_neighbor(int u,
int exclude = -1) const {
vector<array<int, 2>> res;
for (auto id : adj[u]) {
if (id == exclude || ignore && ignore(id)) continue;
res.push_back({operator()(u, id), edge[id].cost});
}
return res;
}
void clear() {
for (auto [u, v, w] : edge) {
adj[u].clear();
adj[v].clear();
}
edge.clear();
ignore = {};
}
graph transpose()
const { // the transpose of the directed graph
graph res(n);
for (auto id = 0; id < (int)edge.size(); ++id) {
if (ignore && ignore(id)) continue;
res.orient(edge[id].to, edge[id].from,
edge[id].cost);
}
return res;
}
int degree(
int u) const { // the degree (outdegree if directed) of
// u (without the ignoration rule)
return (int)adj[u].size();
}
// The adjacency list is sorted for each vertex.
vector<vector<int>> get_adjacency_list() const {
vector<vector<int>> res(n);
for (auto u = 0; u < n; ++u)
for (auto id : adj[u]) {
if (ignore && ignore(id)) continue;
res[(*this)(u, id)].push_back(u);
}
return res;
}
void set_ignoration_rule(const function<bool(int)> &f) {
ignore = f;
}
void reset_ignoration_rule() { ignore = nullptr; }
friend ostream &operator<<(ostream &out,
const graph &g) {
for (auto id = 0; id < (int)g.edge.size(); ++id) {
if (g.ignore && g.ignore(id)) continue;
auto &e = g.edge[id];
out << "{" << e.from << ", " << e.to << ", "
<< e.cost << "}\n";
}
return out;
}
};
// https://github.com/Aeren1564/Algorithms/blob/master/Algorithm_Implementations_Cpp/Graph_Theory/Special_Graphs/functional_graph_processor.sublime-snippet
struct functional_graph_processor {
functional_graph_processor() {}
functional_graph_processor(const vector<int> &next) {
init((int)next.size());
build(next);
}
template<class Graph_t>
template <class Graph_t>
functional_graph_processor(const Graph_t &g) {
init(g.n);
build(g);
Expand Down Expand Up @@ -236,60 +98,8 @@ struct functional_graph_processor {
}
}
}
// Requires graph
template<class Graph> void build(const Graph &g) {
int n = g.n;
assert(n == (int)g.edge.size());
vector<int> pv(n, -1), state(n), on_cycle(n);
vector<vector<int>> cycle;
auto dfs = [&](auto self, int u, int p) -> void {
state[u] = 1;
for (auto id : g.adj[u]) {
if (g.ignore && g.ignore(id)) continue;
auto &e = g.edge[id];
int v = g(u, id);
if (v == p) continue;
if (state[v] == 1) {
cycle.emplace_back();
for (auto w = u; w != v; w = pv[w]) {
cycle.back().push_back(w);
on_cycle[w] = true;
}
cycle.back().push_back(v);
on_cycle[v] = true;
} else if (state[v] == 0) {
pv[v] = u;
self(self, v, u);
}
}
state[u] = 2;
};
for (auto u = 0; u < n; ++u) {
if (state[u] != 2) {
assert(state[u] == 0);
dfs(dfs, u, -1);
}
}
vector<int> next(n, -1);
auto dfs2 = [&](auto self, int u, int p) -> void {
for (auto id : g.adj[u]) {
if (g.ignore && g.ignore(id)) continue;
auto &e = g.edge[id];
int v = g(u, id);
if (v == p || on_cycle[v]) continue;
next[v] = u;
self(self, v, u);
}
};
for (auto &c : cycle) {
for (auto i = 0; i < (int)c.size(); ++i)
next[c[i]] = c[(i + 1) % (int)c.size()];
for (auto u : c) dfs2(dfs2, u, -1);
}
build(next);
}
friend ostream &operator<<(ostream &out,
const functional_graph_processor &fgp) {
const functional_graph_processor &fgp) {
out << "\nCycles: {\n";
for (auto i = 0; i < (int)fgp.cycle.size(); ++i) {
out << " {";
Expand Down Expand Up @@ -324,23 +134,23 @@ struct functional_graph_processor {
}
int n;
vector<vector<int>> cycle;
vector<int> cycle_id; // id of the cycle it belongs to,
// -1 if not part of one
vector<int> cycle_pos; // position in its cycle, -1 if
// not part of one
vector<int> cycle_prev; // previous vertex in its cycle,
// -1 if not part of one
vector<int> component_size; // size of its weakly
// connected component
vector<int> root_of; // first reachable node in a cycle
vector<int> depth; // distance to its root
vector<int> cycle_id; // id of the cycle it belongs to,
// -1 if not part of one
vector<int> cycle_pos; // position in its cycle, -1 if
// not part of one
vector<int> cycle_prev; // previous vertex in its cycle,
// -1 if not part of one
vector<int> component_size; // size of its weakly
// connected component
vector<int> root_of; // first reachable node in a cycle
vector<int> depth; // distance to its root
vector<vector<int>>
abr; // forest of arborescences of reversed edges not
// on the cycles
vector<int> order; // dfs order of abr
vector<int> pos; // pos in the dfs order
vector<int> end; // [pos[u], end[u]) denotes the subtree
vector<int> size; // size of the subtree in abr
abr; // forest of arborescences of reversed edges not
// on the cycles
vector<int> order; // dfs order of abr
vector<int> pos; // pos in the dfs order
vector<int> end; // [pos[u], end[u]) denotes the subtree
vector<int> size; // size of the subtree in abr
};
int main() {
cin.tie(0)->sync_with_stdio(0);
Expand All @@ -356,16 +166,16 @@ int main() {
assert(t[i].root_of == fgp.root_of[i]);
assert(t[i].childs == fgp.abr[i]);
assert(t[i].cyc_pos.has_value() ==
(fgp.cycle_id[i] != -1));
(fgp.cycle_id[i] != -1));
if (auto id = t[i].cyc_pos) {
int cyc_len = ssize(cycle[id->first]);
assert(i == cycle[id->first][id->second]);
assert(
cycle[id->first][(id->second + 1) % cyc_len] ==
a[i]);
cycle[id->first][(id->second + 1) % cyc_len] ==
a[i]);
assert(fgp.cycle_prev[i] ==
cycle[id->first]
[(id->second - 1 + cyc_len) % cyc_len]);
cycle[id->first]
[(id->second - 1 + cyc_len) % cyc_len]);
} else {
assert(fgp.cycle_prev[i] == -1);
}
Expand Down

0 comments on commit 15f5bd3

Please sign in to comment.