use std::cmp::{self, Ordering};
use std::collections::*;
use std::io::{self, Read};

const MOD: usize = 1000000007;

fn main() {
    let stdin = io::stdin();
    let mut sc = Scanner::new(stdin.lock());

    let n: usize = sc.read().unwrap();
    let m: usize = sc.read().unwrap();
    let ab: Vec<_> = (0..m)
        .map(|_| {
            let ai: usize = sc.read().unwrap();
            let bi: usize = sc.read().unwrap();
            (ai - 1, bi - 1)
        })
        .collect();

    // 不便さの最大値 (全ての橋が崩落したときの不便さ)
    // 行き来できなくなった島の組 (a, b) は
    //   (1, 2), (1, 3), ..., (1, n)
    //           (2, 3), ..., (2, n)
    //                   ...
    //                    (n - 1, n)
    // 従って (n - 1) + (n - 2) + ... + 1
    //      = ∑ [n = 1 → n - 1] n
    //      = (n * (n - 1)) / 2
    let max = (n * (n - 1)) / 2;

    let mut ans = Vec::with_capacity(m);
    ans.push(max);

    let mut uf = UnionFind::new(n);
    for &(ai, bi) in ab.iter().rev() {
        if !uf.same(ai, bi) {
            let r = *ans.last().unwrap();
            let sa = uf.size(ai);
            let sb = uf.size(bi);
            ans.push(r - sa * sb);
        } else {
            let r = *ans.last().unwrap();
            ans.push(r);
        }
        uf.merge(ai, bi);
    }

    for i in (0..m).rev() {
        println!("{}", ans[i]);
    }
}

struct UnionFind {
    n: usize,
    root: Vec<usize>,
    rank: Vec<usize>,
    size: Vec<usize>,
}

impl UnionFind {
    fn new(n: usize) -> UnionFind {
        UnionFind {
            n: n,
            root: (0..n).collect(),
            rank: vec![0; n],
            size: vec![1; n],
        }
    }

    fn root(&mut self, x: usize) -> usize {
        let r = self.root[x];
        if r == x {
            r
        } else {
            self.root[x] = self.root(r);
            self.root[x]
        }
    }

    fn merge(&mut self, x: usize, y: usize) {
        let rx = self.root(x);
        let ry = self.root(y);
        if rx == ry {
            return;
        }

        if self.rank[rx] < self.rank[ry] {
            self.root[rx] = ry;
            self.size[ry] += self.size[rx];
        } else {
            self.root[ry] = rx;
            self.size[rx] += self.size[ry];
            if self.rank[rx] == self.rank[ry] {
                self.rank[rx] += 1;
            }
        }
    }

    fn size(&mut self, x: usize) -> usize {
        let rx = self.root(x);
        self.size[rx]
    }

    fn same(&mut self, x: usize, y: usize) -> bool {
        self.root(x) == self.root(y)
    }
}

struct Scanner<R: Read> {
    reader: R,
}

impl<R: Read> Scanner<R> {
    fn new(reader: R) -> Scanner<R> {
        Scanner { reader: reader }
    }

    fn read<T: std::str::FromStr>(&mut self) -> Option<T> {
        self.reader
            .by_ref()
            .bytes()
            .map(|b| b.unwrap() as char)
            .skip_while(|c| c.is_whitespace())
            .take_while(|c| !c.is_whitespace())
            .collect::<String>()
            .parse()
            .ok()
    }

    fn read_vec<T: std::str::FromStr>(&mut self, n: usize) -> Option<Vec<T>> {
        (0..n).map(|_| self.read()).collect()
    }

    fn read_vec2d<T: std::str::FromStr>(&mut self, m: usize, n: usize) -> Option<Vec<Vec<T>>> {
        (0..m).map(|_| self.read_vec(n)).collect()
    }

    fn read_board(&mut self, n: usize) -> Option<Vec<Vec<char>>> {
        (0..n)
            .map(|_| {
                self.read::<String>()
                    .map(|s| s.chars().collect::<Vec<char>>())
            })
            .collect()
    }
}


Measured memory_bytes: 11516