import java.io.*;
import java.util.*;

public class Solution implements Runnable {

	class DSU{
		int[] arr;
		DSU(int n) {
			arr = new int[n];
			for(int i=0;i<n;++i)
				arr[i]=i;
		}
		
		int get(int v){
			if(arr[v]==v)
				return v;
			return arr[v]=get(arr[v]);
		}
		
		void union(int a,int b){
			arr[get(a)]=get(b);
		}
	}
	
	class Edge{
		int a,b;

		Edge(int a, int b) {
			this.a = a;
			this.b = b;
		}
	}
	
	void solve() throws IOException {
		int n=nextInt(),m=nextInt();
		Edge[] edges = new Edge[m];
		int[] deg = new int[n];
		boolean[] is_useful = new boolean[n];
		for(int i=0;i<m;++i){
			edges[i] = new Edge(nextInt()-1,nextInt()-1);
			++deg[edges[i].a];
			++deg[edges[i].b];
		}

		int minIndex = 0;
		for(int i=0;i<n;++i){
			if(deg[i]<deg[minIndex]){
				minIndex = i;
			}
		}


		ArrayList<Integer> useful = new ArrayList<Integer>();
		useful.add(minIndex);

		for(Edge edge : edges){
			if(edge.b == minIndex){
				int tmp = edge.a;
				edge.a=edge.b;
				edge.b=tmp;
			}
			
			if(edge.a == minIndex){
				is_useful[edge.b] = true;
				useful.add(edge.b);
			}
		}

		Collections.sort(useful);
		HashMap<Integer, Integer> ht = new HashMap<Integer, Integer>();
		for(int i=0;i<useful.size();++i)
			ht.put(useful.get(i),i);
		int[] toUnUse = new int[useful.size()];
		boolean [][] graph = new boolean[useful.size()][useful.size()];
		
		for(Edge edge : edges){
			if(is_useful[edge.a] && is_useful[edge.b]){
				graph[ht.get(edge.a)][ht.get(edge.b)] = true;
			}
			else if(is_useful[edge.a]){
				++toUnUse[ht.get(edge.a)];
			}
			else if(is_useful[edge.b]){
				++toUnUse[ht.get(edge.b)];
			}
		}

		for(int i=0;i<useful.size();++i){
			if(toUnUse[i] == n-useful.size() + 1){
				graph[i][ht.get(minIndex)] = true;
			}
		}

		DSU dsu = new DSU(n);

		for(int i=0;i<useful.size();++i)
			for(int j=0;j<useful.size();++j)
				if(!graph[i][j] && !graph[j][i])
					dsu.union(i,j);

		ArrayList<Integer>[] anses = new ArrayList[useful.size()];
		for(int i=0;i<useful.size();++i){
			anses[i] = new ArrayList<Integer>();
		}
		
		for(int i=0;i<n;++i){
			anses[dsu.get(ht.get(is_useful[i]?i : minIndex))].add(i);
		}

		int empty = 0;

		for(int i=0;i<useful.size();++i)
			if(anses[i].isEmpty())
				++empty;

		out.println(useful.size() - empty);

		for(int i=0;i<useful.size();++i){
			if(!anses[i].isEmpty()){
				out.print(anses[i].size());
				for(Integer j: anses[i]){
					out.print(" "+(j+1));
				}
				out.println();
			}
		}
	}

	public static void main(String[] args) {
		new Solution().run();
	}

	PrintWriter out;
	StringTokenizer st;
	BufferedReader br;

	public void run() {
		out = new PrintWriter(System.out);
		br = new BufferedReader(new InputStreamReader(System.in));
		try {
			solve();
		} catch (IOException e) {
			out.println("IOException:");
			out.println(e.getStackTrace());
		}
		out.flush();
	}

	public String nextString() throws IOException {
		while (st == null || !st.hasMoreTokens()) {
			st = new StringTokenizer(br.readLine());
		}
		return st.nextToken();
	}

	public int nextInt() throws IOException {
		return Integer.parseInt(nextString());
	}

	public double nextDouble() throws IOException {
		return Double.parseDouble(nextString());
	}

	public long nextLong() throws IOException {
		return Long.parseLong(nextString());
	}


}