#ifndef DECREMENTAL_SCC_H_ #define DECREMENTAL_SCC_H_ #include "graph/digraph.h" #include "graph/scc.h" #include "algorithm/tarjan.h" #include "algorithm/bfs.h" #include "algorithm/roditty_zwick.h" using namespace graph; namespace algo { template class DecrementalSCC : public RodittyZwick { public: DecrementalSCC(Digraph G) : G(G) {} // void init(); // bool query(const T& u, const T& v); // void remove(const T& u, const T& v); private: Digraph G; // Array used to answer strong connectivity queries in O(1) time std::map A; // Connect SCC/SCC representative with 2 SPTs // pair.first: Shortest-paths out-tree // pair.second: Shortest-paths in-tree std::map, Digraph>> SPT; // Connect each representative with its SCC std::map> connection; }; template void DecrementalSCC::init() { auto SCCs = Tarjan(G).findSCC(); for (auto& C : SCCs) { const auto& w = C.representative(); // Create shortest-paths out-tree/in-tree auto outTree = BFS(C).run(w); SPT[w] = std::make_pair(outTree, outTree.reverse()); // Update A with current SCCs vertices for (const auto& v : C.vertices) A[v] = w; // Link SCC with its representative w connection[w] = C; } } template bool DecrementalSCC::query(const T& u, const T& v) { return A[u] == A[v]; } template void DecrementalSCC::remove(const T& u, const T& v) { // If u and v are not in the same SCC, do nothing if (A[u] != A[v]) return; const auto& w = A[u]; // If edge e(u, v) is not contained in In(w) and Out(w), do nothing if (!SPT[w].first.vertices.contains(w) && !SPT[w].second.vertices.contains(w)) return; // Update In(w) and Out(w) auto inTree = BFS(connection[w]).run(w); SPT[w] = std::make_pair(inTree, inTree.reverse()); if (!SPT[w].second.vertices.contains(u) || !SPT[w].first.vertices.contains(v)) { // TODO: Decompose C into C1, C2, ... Ck } } }; // namespace algo #endif