Suppose you have a graph that has vertices and edges and queries to check if and are in the same connected component.
Use a data structure called Union Find, which can merge two connected components into one in with is the inverse Ackermann function, which grows slower than .
For each edge , we call merge(, ) to merge the connected component containing with the connected component containing .
For each query , we call find_parent() and find_parent(). If find_parent() = find_parent(), then and are in the same connected component.
const int maxn = 100000;
// parent[i] store the temporary parent of vertex i.
// if i == parent[i], then i is the root of a connected component
int parent[maxn+1];
void init()
{
for (int i=1; i<=n; i++)
parent[i]=i;
}
int find_parent(int x)
{
if (parent[x]==x) return x;
else return parent[x]=find_parent(parent[x]);
// see Optimization
}
void merge(int x,int y)
{
parent[find_parent(x)]=find_parent(y);
// by merging like this, the path will be compressed faster
}
We can do path compression by connecting the nodes to their parents directly when we find their parents for the first time, so that when we find their parents again, the complexity of find_parent() becomes .
Given a directed graph, find a way to order the vertices so that if there is an edge , must come before .