#include <bits/stdc++.h>
#define REP(i, a, n) for (int i = (a); i < (int)(n); ++i)
#define REPC(i, a, n) for (int i = (a); i <= (int)(n); ++i)
#define ALL(t) t.begin(), t.end()
#define RALL(t) t.rbegin(), t.rend()
#define MATINIT(type, row, col, init) \
  vector<vector<type>>(row, vector<type>(col, init));
#define Yes(cond) cout << (cond ? "Yes" : "No") << endl;
#define YES(cond) cout << (cond ? "YES" : "NO") << endl;
using namespace std;
using LL = long long;
using ULL = unsigned long long;
template <class T>
using VEC = std::vector<T>;
template <class T>
using MAT = std::vector<std::vector<T>>;
void DUMP() { cerr << endl; }
template <class Head, class... Tail>
void DUMP(Head &&head, Tail &&... tail) {
  cerr << head << ", ";
  DUMP(std::move(tail)...);
}
template <typename T>
ostream &operator<<(ostream &os, vector<T> &vec) {
  os << "{";
  for (auto v : vec) os << v << ",";
  os << "}";
  return os;
}
template <typename T>
ostream &operator<<(ostream &os, set<T> &s) {
  os << "{";
  for (auto p : s) os << p << ",";
  os << "}";
  return os;
}
template <typename T1, typename T2>
ostream &operator<<(ostream &os, map<T1, T2> &m) {
  os << "{";
  for (auto p : m) os << p << ",";
  os << "}";
  return os;
}
template <typename T1, typename T2>
ostream &operator<<(ostream &os, pair<T1, T2> p) {
  os << "[" << p.first << " " << p.second << "]";
  return os;
}
class DisjointSet {
  //参考 蟻本p84
  //均し計算量O(α(N))でほぼ定数

 public:
  static const int MAX_N = 1e6;

  int par[MAX_N];   // parent
  int rank[MAX_N];  // the depth of trees
  int size[MAX_N];  // the size of sets
  int element_num;  // the number of elements
  // n要素で初期化
  DisjointSet(int n) {
    element_num = n;
    for (int i = 0; i < n; ++i) {
      par[i] = i;
      rank[i] = 0;
      size[i] = 1;
    }
  }

  // 木の根を求める
  int find(int x) {
    if (par[x] == x) {
      return x;
    } else {
      return par[x] = find(par[x]);
    }
  }

  // xとyの属する集合を併合
  void unite(int x, int y) {
    x = find(x);
    y = find(y);
    if (x == y) return;
    if (rank[x] < rank[y]) {
      par[x] = y;
      size[y] += size[x];

    } else {
      par[y] = x;
      size[x] += size[y];
      if (rank[x] == rank[y]) rank[x]++;
    }
  }

  // xとyが同じ集合に属するか否か
  bool same(int x, int y) { return find(x) == find(y); }

  friend ostream &operator<<(ostream &os, const DisjointSet &d);
};
ostream &operator<<(ostream &os, const DisjointSet &d) {
  os << "i, p, r, s" << endl;
  for (int i = 0; i < d.element_num; ++i) {
    os << i << ", " << d.par[i] << ", " << d.rank[i] << ", " << d.size[i]
       << endl;
  }
  return os;
}
// LL numOfPath(DisjointSet &ds) {
//   int n = ds.element_num;
//   LL sum = 0;
//   REP(i, 0, n) {
//     LL s = ds.size[i];
//     if (i == ds.find(i) && s >= 2) {
//       sum += s * (s - 1) / 2;
//     }
//   }

//   return sum;
// }
int main() {
  //   cout<<"0"<<endl;
  // auto d = DisjointSet(10);
  // cout<<"1"<<endl;
  // d.unite(1, 2);
  // cout<<"2"<<endl;
  // d.unite(2, 3);
  // d.unite(4, 5);
  // d.unite(6, 7);
  // d.unite(5, 7);
  // cout<<"Display"<<endl;
  // std::cout << d << endl;
  // cout<<d.same(5,7)<<endl;
  // std::cout << d << endl;
  LL N, M;
  cin >> N >> M;
  VEC<pair<int, int>> edge(M);
  REP(i, 0, M) {
    cin >> edge[i].first >> edge[i].second;
    edge[i].first--;
    edge[i].second--;
  }
  reverse(ALL(edge));
  LL U = N * (N - 1) / 2;
  DisjointSet ds(N);
  list<LL> ans;
  LL sum = 0;
  REP(i, 0, M) {
    ans.push_back(U - sum);
    int x = ds.find(edge[i].first);
    int y = ds.find(edge[i].second);
    if (x != y) {
      sum += (LL)ds.size[x] * ds.size[y];
      ds.unite(x, y);
    }
  }
  for (auto it = ans.rbegin(); it != ans.rend(); ++it) {
    cout << *it << endl;
  }
}

Measured memory_bytes: 13568