Domain: Algorithms & Data Structures

## Edge-interval cactus counting

You have an undirected graph on `N` vertices with `M` edges in a fixed order `E1..EM`.

A connected component is **cactus-like** if every edge belongs to at most one simple cycle.  
The graph is **dune-stable** if each connected component is cactus-like.

Count pairs `(L, R)` with `1 ≤ L ≤ R ≤ M` such that the subgraph using only edges
`EL, EL+1, …, ER` is dune-stable.

### Input
- Two integers `N` and `M`
- Then `M` lines, the endpoints of edge `Ei`

### Output
- One integer, the number of valid `(L, R)` pairs


Grading rubric:
criterion: Does the response define a dune-stable graph as one whose every connected component is cactus-like?
weight: 10
criterion: Does the response state that dune-stability is preserved under deleting edges?
weight: 10
criterion: Does the response state that for each fixed L, the number of valid intervals starting at L equals R - L + 1 after maximizing R?
weight: 10
criterion: Does the response describe the edge-as-vertex transformation by introducing a vertex mid(e) for each original edge e?
weight: 10
criterion: Does the response state the invariant that each simple cycle has exactly one non-tree edge excluded from the maintained spanning forest?
weight: 10
criterion: Does the response state that inserting an edge that closes a cycle is rejected when the tree path between its endpoints contains a used-marked edge?
weight: 10
criterion: Does the response state that the excluded non-tree edge for a newly formed cycle is chosen as the minimum-index edge on that cycle?
weight: 10
criterion: Does the response state that marking cycle edges is implemented by a lazy path update that sets used to 1 on a link-cut tree path?
weight: 10
criterion: Does the response state that deleting an excluded non-tree cycle edge triggers a path update that sets used to 0 on the path between its endpoints?
weight: 10
criterion: Does the response state that deleting a tree edge is handled by cutting it from the maintained spanning forest?
weight: 10

Answer:
## Expert solution 

**Terminology.** The prompt calls a graph **dune-stable** if every connected component is cactus-like (each edge lies on at most one simple cycle). I will refer to this same property as **desert** below: **desert ⇔ dune-stable**.

### Monotonicity (enables two pointers)
- If a graph is desert (dune-stable), **deleting edges** cannot create a violation, so it stays desert.  
- If a graph is **not** desert, **adding edges** cannot fix the existence of an edge that already lies on two different simple cycles, so it stays not desert.  

Therefore, for each fixed `L` there exists a maximal `R(L)` such that the window `[L..R(L)]` is desert, and all `[L..R]` with `R ≤ R(L)` are also desert.

### Two pointers and counting formula
Maintain a sliding window `[L..R]` that is always desert. For each `L`:
1. Extend `R` as far as possible while keeping the window desert.
2. Once `R` is maximal, the number of valid pairs starting at `L` equals **`R − L + 1`**.
3. Add **`R − L + 1`** to the answer.
4. Remove edge `E_L` and increment `L`.

### Invariant: spanning forest with “one excluded edge per cycle”
Maintain a spanning forest of the current window graph.

In a cactus component, every simple cycle is represented by:
- exactly one **special** cycle edge that is **not** in the spanning tree, and
- all other edges of the cycle are tree edges marked `used = 1` (“this tree edge already belongs to a cycle”).

### Link-Cut Tree (LCT) edge-as-vertex modeling
Because an LCT stores data on vertices, represent each original edge `e_i = (u, v)` by creating a new vertex `mid(i)`.  
Connect `u—mid(i)` and `mid(i)—v` in the LCT when the edge is in the spanning forest.

Store metadata on `mid(i)`:
- `idx(mid(i)) = i`
- `used(mid(i)) ∈ {0,1}`

Maintain path aggregates over edge-vertices:
- `minIdx` on a path (minimum `idx` among edge-vertices on the path)
- `maxUsed` on a path (maximum `used` among edge-vertices on the path)

Use lazy propagation to assign `used := 0` or `used := 1` on all edge-vertices along an LCT path.

### Insert edge `e_i = (u, v)` at the right boundary
Let `x = u`, `y = v`, and let `mid(i)` be the edge-vertex.

**Case A: `x` and `y` are disconnected.**
- Link `x—mid(i)—y` into the forest.
- No cycle is created.

**Case B: `x` and `y` are already connected.**
- The unique tree path `P(x, y)` plus the new edge forms one simple cycle.
- Query `maxUsed` on `P(x, y)`.
  - If `maxUsed = 1`, adding this edge would force an edge to lie on two cycles → window becomes invalid.
  - If `maxUsed = 0`, the cycle is allowed.

**Choosing the special excluded edge**
- The cycle edges are exactly: edges on `P(x, y)` plus the new edge `i`.
- Since edges are appended in increasing index order, `i` is the largest index on the cycle.
- Therefore the smallest-index cycle edge is the minimum `idx` on `P(x, y)`, obtainable by an LCT path-min query.

**Update**
- Cut that minimum-index edge-vertex from the spanning tree (it becomes the special excluded edge).
- Link `x—mid(i)—y` into the spanning tree.
- Apply a lazy path update `used := 1` on `P(x, y)` in the new tree.

### Delete edge `E_L` when moving the left boundary
Track for each edge whether it is currently linked in the spanning forest (tree edge) or excluded as the special non-tree edge.

- If `E_L` is the special excluded non-tree edge:
  - Deleting it destroys that cycle.
  - Apply a lazy path update `used := 0` on the tree path between its endpoints.

- If `E_L` is a tree edge:
  - Cut its edge-vertex `mid(L)` from the spanning forest.

### Complexity justification
Each insertion/deletion performs a constant number of LCT operations (path query, path update, link, cut).  
Each LCT operation is `O(log N)` amortized.  
Two pointers performs `O(M)` insertions and `O(M)` deletions total.  
Total time: **`O(M log N)`**.