You can do this fairly easily in almost-linear, O(E * alpha(V))
time, where alpha is the ridiculously-slowly-growing inverse-Ackermann function, using a disjoint-set data structure. The trick is to reverse S
and add edges, so you ask about when G
first becomes connected, rather than disconnected. The incremental connectivity problem is quite a bit easier than the decremental connectivity case.
Given an implementation of disjoint-set, you can augment it to track the number of components, and a graph is connected exactly when there is only one component. If you start with n
components, then before any Union(x, y)
operation, check whether x
and y
belong to the same component. If they don't, then the union operation will reduce the graph's components by 1.
For your graph, you'll need to preprocess S
to find all of the edges in G
that are not in S
, and add these to the disjoint-set data structure first. Then, if adding S[i]
causes the graph to be connected for the first time, the answer is i
, since we've already added S[i+1], S[i+2], ... S[n-1]
.
Optimal Complexity
The inverse-Ackermann function is at most 4
for any input that fits in our universe, so our Union-find algorithm is usually considered 'pretty much linear'. However, if that's not good enough...
You can do this in O(V+E)
, although it's quite complex, and probably of mostly theoretical interest. Gabow and Tarjan's 1984 paper found an algorithm that supports Union-Find in O(1)
amortized cost per operation if we know the order of all union operations, which we do here. It still uses the disjoint-set data structure, but adds additional auxiliary structures to cache node information on small sets.
Some pseudocode is provided in the paper, but you'll probably need to implement this yourself or look for implementations online. It also only works in the word RAM model, since it fundamentally relies on manipulating small bit-strings in constant time to use them as lookup tables (a fairly standard assumption, but you'll need to do some low-level bit manipulation).