An articulation point (or cut vertex) of an undirected graph is a vertex whose removal increases the number of connected components. (For a vertex with incident edges, removal also removes its edges.) Your task is to implement the function `articulation_points(n, edges)` that, given the number of vertices `n` (vertices are labeled `0` to `n-1`) and a list of undirected edges `edges` (each edge given as a tuple `(u, v)`), returns a list containing all articulation points of the graph. The list must be sorted in ascending order. If there are no articulation points, return an empty array.
The graph may be disconnected. Isolated vertices (with no edges) and vertices of degree 1 can never be articulation points (removing a degree‑1 vertex does not disconnect the graph). Multiple edges between the same pair of vertices should be treated as a single edge (i.e., the graph is simple).
You need to implement the function `articulation_points(n, edges)` where:
- `n` is an integer, the number of vertices.
- `edges` is a list of tuples, each `(u, v)` representing an undirected edge.
Return a list of integers (the articulation points) in ascending order.
Constraints
Constraints:
- `1 <= n <= 10^5`
- `0 <= len(edges) <= 10^5`
- Input graph may have multiple edges, but they should be treated as simple.
- The graph may be disconnected.
- Complexity requirement: O(n + m) time, O(n + m) space.