#include <bits/stdc++.h>
using namespace std;
bool changed[222222];
pair<int, int> edges[222222];
set<pair<int, int> > adj[111111];
bool visited[111111];
deque<pair<int, int> > to_connect;
vector<int> Harry;
char outbuf[12000000];
char* out = outbuf;
int moves = 0;
void flush_harry() {
  out += sprintf(out, "%d", Harry.size());
  for (int v : Harry) {
    out += sprintf(out, " %d", v);
  }
  out += sprintf(out, "\n");
  Harry.clear();
}
void move_stairs(int id, int u, int v) {
  ++moves;
  flush_harry();
  adj[edges[id].first].erase(pair<int, int>(edges[id].second, id));
  adj[edges[id].second].erase(pair<int, int>(edges[id].first, id));
  edges[id].first = u, edges[id].second = v;
  adj[u].insert(pair<int, int>(v, id));
  adj[v].insert(pair<int, int>(u, id));
  out += sprintf(out, "%d %d %d\n", id, u, v);
  changed[id] = true;
}
vector<int> in_component;
bool dfs1(int v, int parent_edge, bool connected_to_one) {
  visited[v] = true;
  in_component.push_back(v);
  int edge_to_move = -1;
  for (auto& p : adj[v]) {
    if (!connected_to_one && visited[p.first] && parent_edge != p.second) {
      edge_to_move = p.second;
      connected_to_one = true;
    } else if (!visited[p.first]) {
      connected_to_one = dfs1(p.first, p.second, connected_to_one);
    }
  }
  if (edge_to_move != -1) {
    move_stairs(edge_to_move, v, 1);
  }
  return connected_to_one;
}
void dfs2(int v, int parent_edge) {
  if (v != 1) Harry.push_back(v);
  visited[v] = true;
  for (auto& p : adj[v])
    if (!visited[p.first]) {
      dfs2(p.first, p.second);
      Harry.push_back(v);
    }
  vector<pair<int, int> > to_change;
  for (auto& p : adj[v])
    if (p.second != parent_edge && !to_connect.empty() && !changed[p.second]) {
      to_change.push_back(pair<int, int>(p.second, to_connect.back().second));
      to_connect.pop_back();
    }
  for (auto& p : to_change) {
    move_stairs(p.first, v, p.second);
    dfs2(p.second, p.first);
    Harry.push_back(v);
  }
}
int main() {
  int N, M;
  scanf("%d%d", &N, &M);
  for (int i = (0); i < (M); ++i) {
    int a, b;
    scanf("%d%d", &a, &b);
    adj[a].insert(pair<int, int>(b, i + 1));
    adj[b].insert(pair<int, int>(a, i + 1));
    edges[i + 1].first = a, edges[i + 1].second = b;
  }
  Harry.push_back(1);
  for (int i = (1); i < (N + 1); ++i)
    if (!visited[i]) {
      bool connected_to_one = dfs1(i, -1, i == 1);
      if (!connected_to_one) {
        for (int& v : in_component)
          if (adj[v].size() <= 1) {
            to_connect.push_back(pair<int, int>(in_component.size(), v));
            break;
          }
      }
      in_component.clear();
    }
  sort(to_connect.begin(), to_connect.end());
  for (int i = (1); i < (N + 1); ++i) visited[i] = false;
  dfs2(1, -1);
  while (!to_connect.empty() && to_connect.back().first > 1) {
    int v = to_connect.back().second;
    to_connect.push_front(pair<int, int>(1, v));
    to_connect.pop_back();
    pair<int, int> n = *adj[v].begin();
    move_stairs(n.second, 1, n.first);
    dfs2(n.first, n.second);
    Harry.push_back(1);
  }
  flush_harry();
  if (!to_connect.empty()) {
    printf("NO\n");
    return 0;
  }
  printf("YES\n%d\n", moves);
  printf("%s\n", outbuf);
}
