#ifndef RODITTY_ZWICK_SCC_H_ #define RODITTY_ZWICK_SCC_H_ #include "algorithm/decremental_reachability.h" #include "algorithm/tarjan.h" #include "graph/breadth_first_tree.h" namespace algo { template class RodittyZwick : public DecrementalReachability { public: RodittyZwick() = default; explicit RodittyZwick(graph::Digraph G) { this->G = G; } // void init() override; // void findSCC(graph::Digraph G); // Return true if u and v are in the same SCC bool query(const T& u, const T& v) override; // Delete collection of edges void remove(const std::vector>& edges) override; // Remove edge (u,v) and update A accordingly for fast checking query void remove(const T& u, const T& v); std::unordered_map> getSCCs() { return C; } private: // Array used to answer strong connectivity queries in O(1) time std::unordered_map A; // Connect each representative with its SCC std::unordered_map> C; // Maintain in-out bfs trees std::unordered_map> In; std::unordered_map> Out; }; template void RodittyZwick::init() { findSCC(this->G); } template void RodittyZwick::findSCC(graph::Digraph G) { auto SCCs = Tarjan(G.adjList).execute(); for (auto& SCC : SCCs) { const auto& w = SCC.id; for (const auto& v : SCC.vertices()) A[v] = w; Out[w] = BreadthFirstTree(SCC, w); In[w] = BreadthFirstTree(SCC.reverse(), w); C[w] = SCC; } } template bool RodittyZwick::query(const T& u, const T& v) { return A[u] == A[v]; } template void RodittyZwick::remove(const std::vector>& edges) { for (const auto& [u, v] : edges) remove(u, v); } template void RodittyZwick::remove(const T& u, const T& v) { const auto& w = A[u]; C[w].remove(u, v); this->G.remove(u, v); // If u and v are not in the same SCC, do nothing if (A[u] != A[v]) return; // If edge (u,v) is not contained in both inTree and outTree do nothing if (!In[w].adjList[u].contains(v) && !Out[w].adjList[u].contains(v)) return; // Update In(w) and Out(w) Out[w] = BreadthFirstTree(C[w], w); In[w] = BreadthFirstTree(C[w].reverse(), w); // If a SCC is broken, compute all SCCs again if (!In[w].adjList.count(u) || !Out[w].adjList.count(v)) findSCC(C[w]); } }; // namespace algo #endif