#ifndef DECREMENTAL_SCC_H_ #define DECREMENTAL_SCC_H_ #include "algorithm/roditty_zwick.h" #include "algorithm/tarjan.h" #include "tree/breadth_first_tree.h" using namespace graph; using namespace tree; namespace algo { template class DecrementalSCC : public RodittyZwick { public: DecrementalSCC(Digraph G) : G(G) {} void init(); void findSCC(); 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; // Maintain in-out bfs trees std::map> inTree; std::map> outTree; // Connect each representative with its SCC std::map> connection; }; template void DecrementalSCC::init() { findSCC(); } template void DecrementalSCC::findSCC() { auto SCCs = Tarjan(G).execute(); for (auto& C : SCCs) { const auto& w = C.representative(); for (const auto& v : C.adjMatrix) A[v.first] = w; outTree[w] = BreadthFirstTree(BreadthFirstSearch(C).execute(w)); inTree[w] = BreadthFirstTree(BreadthFirstSearch(C.reverse()).execute(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) { G.adjMatrix[u].erase(v); // If u and v are not in the same SCC, do nothing if (A[u] != A[v]) return; const auto& w = A[u]; connection[w].remove(u, v); // Update In(w) and Out(w) if they contain the edge if (inTree[w].contains(u, v) || outTree[w].contains(u, v)) { auto C = connection[w]; inTree[w] = BreadthFirstTree(BreadthFirstSearch(C.reverse()).execute(w)); outTree[w] = BreadthFirstTree(BreadthFirstSearch(C).execute(w)); } // If a SCC is broken, compute all SCCs again if (!inTree[w].contains(u) || !outTree[w].contains(v)) { findSCC(); } } }; // namespace algo #endif