1. Abridged Problem Statement
Given an undirected connected graph of N stars (vertices) and M bidirectional tunnels (edges), and two special vertices S (source) and T (target), you must partition some of the edges into as many groups as possible (each group corresponds to one “crystal type”) so that:
- No edge belongs to more than one group.
- For each group, when you remove all edges in that group, there is no path from S to T.
Output the maximum number of groups L, then for each group output its size and the list of edge indices in that group.

2. Detailed Editorial
Goal
Find the maximum number of disjoint edge‐sets (cuts) such that removing any one set disconnects S from T.

Key insight
Every S–T path must use edges that increase the BFS distance from S by exactly +1 at each step. If the shortest-path distance from S to T is D, then any path has D edges that step from distance 0→1, 1→2, …, D–1→D. Removing all edges of one particular “level” i→i+1 in the BFS layering cuts every S–T path.

Algorithm
1. Run a BFS from S, compute dist[v] = distance (in edges) from S to v. Let D = dist[T].
2. The answer L = D, because you can form exactly D disjoint cuts (one at each level), and you cannot have more than D disjoint cuts (each cut must remove ≥1 edge from every S–T path).
3. For each level i = 0…D–1, gather all edges (u,v) whose far endpoint satisfies dist[v]=dist[u]+1=i+1. Those edges form the i-th cut.
4. Output D, then for i=0…D–1 output the size of the i-th list and the edge IDs.

Complexity
- BFS in O(N+M).
- Scanning edges in O(N + total degree) = O(N+M).
Fits N≤400, M up to ~80 000 easily.

3. C++ Solution
```cpp
#include <bits/stdc++.h>

using namespace std;

template<typename T1, typename T2>
ostream& operator<<(ostream& out, const pair<T1, T2>& x) {
    return out << x.first << ' ' << x.second;
}

template<typename T1, typename T2>
istream& operator>>(istream& in, pair<T1, T2>& x) {
    return in >> x.first >> x.second;
}

template<typename T>
istream& operator>>(istream& in, vector<T>& a) {
    for(auto& x: a) {
        in >> x;
    }
    return in;
};

template<typename T>
ostream& operator<<(ostream& out, const vector<T>& a) {
    for(auto x: a) {
        out << x << ' ';
    }
    return out;
};

int n, m, s, t;
vector<vector<pair<int, int>>> adj;

void read() {
    cin >> n >> m >> s >> t;
    s--, t--;
    adj.assign(n, {});
    for(int i = 0; i < m; i++) {
        int u, v;
        cin >> u >> v;
        u--;
        v--;
        adj[u].push_back({v, i});
        adj[v].push_back({u, i});
    }
}

void solve() {
    // We want the maximum number of pairwise edge-disjoint S-T cuts that
    // together cover every S-T path. The answer is the shortest-path distance
    // d = dist(S, T): for each level i in 0..d-1 the set of edges going from a
    // BFS layer i vertex to a layer i+1 vertex forms a valid S-T cut, and these
    // d cuts are edge-disjoint (an edge spans at most one consecutive layer
    // pair). No more than d disjoint cuts can exist because any shortest path
    // has exactly d edges and must be cut by each crystal type. So we BFS from
    // S, bucket every forward edge (dist[v] == dist[u] + 1) by dist[u], and
    // print one crystal type per layer.

    vector<int> dist(n, -1);

    queue<int> q;
    q.push(s);
    dist[s] = 0;

    while(!q.empty()) {
        int u = q.front();
        q.pop();
        for(auto [v, _]: adj[u]) {
            if(dist[v] == -1) {
                dist[v] = dist[u] + 1;
                q.push(v);
            }
        }
    }

    vector<vector<int>> answer(dist[t]);
    for(int u = 0; u < n; u++) {
        assert(dist[u] != -1);
        if(dist[u] >= dist[t]) {
            continue;
        }

        for(auto [v, id]: adj[u]) {
            if(dist[v] == dist[u] + 1) {
                answer[dist[u]].push_back(id + 1);
            }
        }
    }

    cout << dist[t] << '\n';
    for(int i = 0; i < dist[t]; i++) {
        cout << answer[i].size() << ' ' << answer[i] << '\n';
    }
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);

    int T = 1;
    // cin >> T;
    for(int test = 1; test <= T; test++) {
        read();
        // cout << "Case #" << test << ": ";
        solve();
    }

    return 0;
}
```

4. Python Solution
```python
import sys
from collections import deque

def main():
    data = sys.stdin.read().split()
    it = iter(data)
    n = int(next(it))
    m = int(next(it))
    s = int(next(it)) - 1
    t = int(next(it)) - 1

    # Build adjacency list: adj[u] = list of (v, edge_id)
    adj = [[] for _ in range(n)]
    for eid in range(m):
        u = int(next(it)) - 1
        v = int(next(it)) - 1
        adj[u].append((v, eid))
        adj[v].append((u, eid))

    # BFS from s to compute distances
    dist = [-1]*n
    dist[s] = 0
    q = deque([s])
    while q:
        u = q.popleft()
        for v, _ in adj[u]:
            if dist[v] == -1:
                dist[v] = dist[u] + 1
                q.append(v)

    # D = shortest distance from s to t
    D = dist[t]

    # Prepare D lists of edge IDs
    answer = [[] for _ in range(D)]

    # For every node u with dist[u] < D
    for u in range(n):
        du = dist[u]
        if du < 0 or du >= D:
            continue
        # Check each outgoing edge
        for v, eid in adj[u]:
            # select only edges going one layer forward
            if dist[v] == du + 1:
                answer[du].append(eid + 1)  # 1-based

    # Print result
    out = []
    out.append(str(D))
    for level in range(D):
        lst = answer[level]
        out.append(f"{len(lst)} {' '.join(map(str, lst))}")
    sys.stdout.write("\n".join(out))

if __name__ == "__main__":
    main()
```

5. Compressed Editorial
- Compute BFS distances dist[] from S; let D = dist[T].
- The maximum number of disjoint cuts is D.
- For each i=0…D–1, cut-level i consists of all edges (u→v) with dist[u]=i and dist[v]=i+1. These D cuts are edge-disjoint and each blocks all S–T paths.
