#ifndef ITALIANO_H_ #define ITALIANO_H_ #include "algorithm/roditty_zwick.h" #include "algorithm/tarjan.h" #include "graph/breadth_first_tree.h" #include using namespace graph; namespace algo { template class Italiano : public RodittyZwick { public: Italiano(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; // Transitive closure matrix, used to answer reachability queries in O(1) std::map> TC; // Each vertex's reachability tree std::map> RT; // Incoming / Outgoing edges struct Edges { std::forward_list inc; std::forward_list out; }; std::map E; }; template void Italiano::init() { for (const auto& u : std::views::keys(G.adjMatrix)) { for (const auto& v : G.adjMatrix[u]) { E[v].inc.push_front(u); E[u].out.push_front(v); TC[u][v] = false; } RT[u] = BreadthFirstTree(G, u); TC[u][u] = true; for (const auto& v : std::views::keys(RT[u].adjMatrix)) { TC[u][v] = true; } } } template bool Italiano::query(const T& u, const T& v) { return TC[u][v]; } template void Italiano::remove(const T& u, const T& v) { std::map> R; for (const auto& w : std::views::keys(G.adjMatrix)) { if (RT[w].contains(u, v) && std::distance(E[w].inc.begin(), E[w].inc.end()) > 1) { if (E[v].inc.front() == u) { E[v].inc.pop_front(); R[w].push_front(E[v].inc.front()); E[v].inc.push_front(u); } else { R[w].push_front(E[v].inc.front()); } } } E[u].inc.remove(v); E[u].out.remove(u); G.remove(u, v); for (const auto& w : std::views::keys(G.adjMatrix)) { bool hooked = false; // R contains all vertices that need a hook-parent while (!R[w].empty()) { // z is a candidate hook-parent if it is in RT[w] const auto& toHook = R[w].front(); for (const auto& z : E[toHook].inc) { if (RT[w].contains(u, z)) { R[w].remove(toHook); hooked = true; break; } } if (!hooked) { TC[w][toHook] = false; for (const auto& z : E[toHook].out) { if (RT[w].contains(toHook, z)) R[w].push_front(z); } } } } } } // namespace algo #endif