use contest::data::UnionFind;
use contest::io::Scanner;

fn main() {
    let mut sc = Scanner::new(std::io::stdin());
    let n = sc.next::<i64>();
    let m = sc.next::<i64>();
    let mut es = vec![];
    for _ in 0..m as usize {
        let a = sc.next::<usize>() - 1;
        let b = sc.next::<usize>() - 1;
        es.push((a, b));
    }

    let mut uf = UnionFind::new(n as usize);
    let mut value = n * (n - 1) / 2;
    let mut res = vec![];
    for &(a, b) in es.iter().rev() {
        res.push(value);
        if uf.root(a) == uf.root(b) {
            continue;
        }
        value -= uf.size(a) as i64 * uf.size(b) as i64;
        uf.union(a, b);
    }
    for r in res.iter().rev() {
        println!("{}", r);
    }
}
pub mod contest {
    pub mod io {
        /// Scanner
        ///
        /// # Example
        /// ```
        /// use contest::io::Scanner;
        /// let mut sc = Scanner::new("1 2 \n\n \r\t \n 3.5".as_bytes());
        /// assert_eq!("1".to_string(), sc.next::<String>());
        /// assert_eq!(2, sc.next());
        /// assert_eq!(3.5, sc.next());
        ///
        /// // To create a scanner from stdin:
        /// Scanner::new(std::io::stdin());
        /// ```
        use std;
        use std::io;
        use std::io::BufRead;

        pub struct Scanner<R: io::Read> {
            br: io::BufReader<R>,
            // Read tokens are stored in reversed order per line.
            buf: Vec<String>,
        }

        pub fn new<R: io::Read>(r: R) -> Scanner<R> {
            Scanner::new(r)
        }

        impl<R: io::Read> Scanner<R> {
            #[inline]
            pub fn new(r: R) -> Scanner<R> {
                Scanner {
                    br: io::BufReader::new(r),
                    buf: vec![],
                }
            }
            #[inline]
            pub fn next<T>(&mut self) -> T
            where
                T: std::str::FromStr,
                T::Err: std::fmt::Debug,
            {
                self.next_string()
                    .map(|s| s.parse::<T>().expect("Parse failed: "))
                    .expect("Unexpected EOF")
            }
            #[inline]
            pub fn next2<T1, T2>(&mut self) -> (T1, T2)
            where
                T1: std::str::FromStr,
                T2: std::str::FromStr,
                T1::Err: std::fmt::Debug,
                T2::Err: std::fmt::Debug,
            {
                (self.next(), self.next())
            }
            fn next_string(&mut self) -> Option<String> {
                self.buf.pop().or_else(|| match self.update() {
                    true => self.next_string(),
                    false => None,
                })
            }
            #[inline]
            fn update(&mut self) -> bool {
                let mut s = String::new();
                let res = self.br.read_line(&mut s);
                match res.expect("I/O error.") {
                    0 => false,
                    _ => {
                        self.buf = s.split_whitespace().map(|x| x.to_string()).rev().collect();
                        true
                    }
                }
            }
        }

        #[test]
        fn test_next() {
            let mut sc = new("hoge".as_bytes());
            let s: String = sc.next();
            assert_eq!("hoge", s);
        }
    }
    pub mod data {
        /// Implementation of disjoint set union algorithm using link-by-size and path
        /// compression. It performs any intermixed sequence of m >= n find and n - 1
        /// union operations in O(m α(m,n)) time where α is the inverse of the
        /// Ackermann function [Tarjan-van Leeuwen 1984].
        ///
        /// # Examples
        ///
        /// ```
        /// use contest::data::UnionFind;
        /// let mut uf = UnionFind::new(4);
        /// uf.union(0, 1);
        /// assert_eq!(2, uf.size(0));
        /// assert_eq!(uf.root(0), uf.root(1));
        /// ```
        pub struct UnionFind {
            tree: Vec<isize>,
        }

        impl UnionFind {
            /// Creates n disjoint singleton sets.
            #[inline]
            pub fn new(n: usize) -> UnionFind {
                UnionFind { tree: vec![-1; n] }
            }
            /// Returns the root of the tree containing i.
            pub fn root(&mut self, i: usize) -> usize {
                if self.tree[i] < 0 {
                    return i;
                }
                let j = self.tree[i];
                let root = self.root(j as usize);
                // Path decomposition.
                self.tree[i] = root as isize;
                root
            }
            /// Returns the size of the tree containing i.
            #[inline]
            pub fn size(&mut self, i: usize) -> usize {
                let root = self.root(i);
                -self.tree[root] as usize
            }
            /// Unions i and j.
            pub fn union(&mut self, i: usize, j: usize) {
                let mut i = self.root(i);
                let mut j = self.root(j);
                if i == j {
                    return;
                }
                if -self.tree[i] > -self.tree[j] {
                    let tmp = i;
                    i = j;
                    j = tmp;
                }
                // Append i to j since size(i) <= size(j).
                self.tree[j] += self.tree[i];
                self.tree[i] = j as isize;
            }
        }

        #[cfg(test)]
        mod test {
            use super::UnionFind;
            #[test]
            fn it_works() {
                let mut uf = UnionFind::new(4);
                uf.union(0, 1);
                assert_eq!(2, uf.size(0));
                assert_eq!(2, uf.size(1));
                assert_eq!(1, uf.size(2));
                uf.union(2, 3);
                uf.union(2, 1);
                assert_eq!(4, uf.size(3));
            }
        }
    }
}


Measured memory_bytes: 9468