Critical
Authors: Benjamin Qi, Mihnea Brebenel
CSES Critical Cities and Extensions
Prerequisites
- Gold - Cycle Finding
Paths
Focus Problem – try your best to solve this problem before continuing!
Resources | ||||
---|---|---|---|---|
Wiki | Wiki Definition | |||
Blog | Well-covered article | |||
Blog | Well-covered article |
Solution
Naive approach
Critical nodes in a DAG are commonly known as dominators. Let's define as the set of nodes that dominate node .
The dominator of the starting node is itself. The set of dominators for any other node is the intersection of the set of dominators for all ancestors of node .
The following code uses the above rucerrence.
C++
#include <bits/stdc++.h>using namespace std;const int NMAX = 1e5;int n, m;vector<int> g[NMAX];vector<bitset<NMAX>> dom;bool seen[NMAX];
Time complexity: .
Unfortunately, this is too slow.
A faster approach
In this approach we attempt building the dominator tree of the graph. A dominator tree is a tree where each node's children are thos nodes it immediately dominates. The start node is the root of the tree. The immediate dominator - or shortly idom - of a node is a node that strictly dominates node and every other dominator of node strictly dominates node . The definition of the dominator tree gives us the following property: If node dominates node , then node is an ancestor of node , thus the answe of the problem is the path from the root to node in the dominator tree.
From now on, we'll discuss the construction of the dominator tree, but first we need to precompute some helpful values:
The following graph depicts the semi-dominator for every node. The full-color edges represent the edges part of the DFS tree.
Important properties
If you're interested in seeing proofs scroll down to the final section.
- If , then is a proper ancestor of is the DFS tree.
- If , then idom(u) is an ancestor - not necessarily proper - of in the DFS tree.
- Let . If, for every vertex which is an ancestor of and has sdom(u) as its proper ancestor, then .
- Let . Let u be a vertex for which is minimum among all vertices u satisfying “ is a proper ancestor of and is an ancestor of ”. If then .
- Let and &v& be a vertex for which is minimum among all vertices satisfying: is a proper ancestor of and is an ancestor of u. If then .
- Let . Let be a vertex for which is minimum among all vertices satisfying “ is a proper ancestor of and is an ancestor of ”. Then:
Precompute Sdom
The following identity enables us the compute :
In other words, is the minimum node in the intersection of the following groups:
- All the nodes with
- where
Implementation
Precompute using a DFS the new mapping of the tree, i.e. the new labels of the nodes are their entry time .
Compute for all nodes by applying the formula mentioned in the previous section. Iterate over node in decreasing order, maintaining the visited nodes in a DSU. Also, the DSU is slightly modified:
- = Let be the root of the components
- If , return ;
- else return a node with minimum sdom, lying on path from to .
In order to process node we iterate over all incoming edges
- If , is an ancestor of , would not have been processed till now, thus would return v.
- If then would have already been processed and would return a node lying on the path from to root in the DSU tree having minimum sdom.
The 2 cases cover precisely the definition .
- Compute the for all nodes by applying .
In this step, store nodes in buckets of their own and iterate over them updating the value using .
This snippet of code combines steps and :
C++
// Iterate decreasinglyfor (int i = n - 1; i >= 0; i--) {// Iterat over incoming edges applying (2)for (int p : rg[i]) { sdom[i] = min(sdom[i], sdom[Find(p, 0)]); }// Insert i into it's bucket after sdom[i]if (i > 0) { bucket[sdom[i]].push_back(i); }// Apply (1) for nodes in bucketfor (int node : bucket[i]) {int p = Find(node, 0);if (sdom[p] == sdom[node]) {
- After steps and , the value has been set (), for every node , or it has been set to an ancestor of and . Now if we start processing nodes after (0) increasingly, then for any vertex :
C++
#include <functional>#include <iostream>#include <set>#include <stack>#include <vector>using namespace std;int main() {int n, m;
Time complexity:
Proofs
Cycles
- GP of Wroclaw 2020 H
- USACO Camp - Acyclic Graphs
Status | Source | Problem Name | Difficulty | Tags | |
---|---|---|---|---|---|
Codeforces | Hard | ||||
Kattis | Hard |
Module Progress:
Join the USACO Forum!
Stuck on a problem, or don't understand a module? Join the USACO Forum and get help from other competitive programmers!