You are given an undirected graph consisting of n vertices. Initially there are no edges in the graph. Also you are given q queries, each query either adds one undirected edge to the graph or removes it. After each query you have to check if the resulting graph is bipartite (that is, you can paint all vertices of the graph into two colors so that there is no edge connecting two vertices of the same color).

Input

The first line contains two integers n and q (2 ≤ n, q ≤ 100000).

Then q lines follow. ith line contains two numbers xi and yi (1 ≤ xi < yi ≤ n). These numbers describe ith query: if there is an edge between vertices xi and yi, then remove it, otherwise add it.

Output

Print q lines. ith line must contain YES if the graph is bipartite after ith query, and NO otherwise.

Example

Input

3 5
2 3
1 3
1 2
1 2
1 2


Output

YES
YES
NO
YES
NO
#include <bits/stdc++.h>
struct DSU {
 private:
  int32_t* parents;
  int32_t* sizes;
  std::vector<std::pair<int32_t, int32_t> > actions;
  int32_t get_root(int32_t v) {
    if (parents[v] == v) return v;
    return get_root(parents[v]);
  }

 public:
  DSU(int32_t n) {
    parents = new int32_t[n];
    sizes = new int32_t[n];
    for (int32_t i = 0; i < n; i++) {
      parents[i] = i;
      sizes[i] = 1;
    }
  }
  bool same(int32_t v1, int32_t v2) { return get_root(v1) == get_root(v2); }
  void join(int32_t v1, int32_t v2) {
    int32_t root1 = get_root(v1), root2 = get_root(v2);
    if (root1 == root2) {
      actions.emplace_back(-1, -1);
      return;
    }
    if (sizes[root1] > sizes[root2]) {
      int32_t tmp = root1;
      root1 = root2;
      root2 = tmp;
    }
    parents[root1] = root2;
    sizes[root2] += sizes[root1];
    actions.emplace_back(root1, root2);
  }
  void pop() {
    if (actions.back().first != -1) {
      sizes[parents[actions.back().first]] -= sizes[actions.back().first];
      parents[actions.back().first] = actions.back().first;
    }
    actions.pop_back();
  }
};
struct Tracker {
 private:
  DSU all_dsu;
  DSU comp_dsu;
  int32_t num_edges = 0;
  int32_t broken_since = -1;
  std::set<int32_t>* graph;
  std::vector<int32_t> actions_time;

 public:
  Tracker(int32_t n) : all_dsu(n), comp_dsu(n) {
    graph = new std::set<int32_t>[n];
  }
  void add_edge(int32_t v1, int32_t v2) {
    if (all_dsu.same(v1, v2)) {
      if (comp_dsu.same(v1, v2)) {
        if (broken_since == -1) broken_since = num_edges;
      } else {
      }
    } else {
      if (graph[v2].size() > 0) {
        comp_dsu.join(v1, *graph[v2].begin());
        actions_time.push_back(num_edges);
      }
      if (graph[v1].size() > 0) {
        comp_dsu.join(v2, *graph[v1].begin());
        actions_time.push_back(num_edges);
      }
    }
    all_dsu.join(v1, v2);
    graph[v1].insert(v2);
    graph[v2].insert(v1);
    num_edges++;
  }
  void pop_edge(int32_t v1, int32_t v2) {
    num_edges--;
    if (num_edges == broken_since) broken_since = -1;
    all_dsu.pop();
    graph[v1].erase(v2);
    graph[v2].erase(v1);
    while (actions_time.size() > 0 && actions_time.back() >= num_edges) {
      comp_dsu.pop();
      actions_time.pop_back();
    }
  }
  bool get_ans() { return broken_since == -1; }
};
std::vector<std::pair<int32_t, int32_t> >* segtree;
void add_edge(int32_t node, int32_t left, int32_t right, int32_t query_left,
              int32_t query_right, std::pair<int32_t, int32_t> edge) {
  if (left >= query_right || right <= query_left) return;
  if (left >= query_left && right <= query_right) {
    segtree[node].push_back(edge);
    return;
  }
  int32_t m = (left + right) / 2;
  add_edge(node * 2 + 1, left, m, query_left, query_right, edge);
  add_edge(node * 2 + 2, m, right, query_left, query_right, edge);
}
void get_ans(int32_t node, int32_t left, int32_t right, Tracker& tracker) {
  for (int32_t i = 0; i < segtree[node].size(); i++)
    tracker.add_edge(segtree[node][i].first, segtree[node][i].second);
  if (right - left == 1) {
    std::cout << (tracker.get_ans() ? "YES" : "NO") << "\n";
    for (int32_t i = 0; i < segtree[node].size(); i++)
      tracker.pop_edge(segtree[node][i].first, segtree[node][i].second);
    return;
  }
  int32_t m = (left + right) / 2;
  get_ans(node * 2 + 1, left, m, tracker);
  get_ans(node * 2 + 2, m, right, tracker);
  for (int32_t i = 0; i < segtree[node].size(); i++)
    tracker.pop_edge(segtree[node][i].first, segtree[node][i].second);
}
int main() {
  int32_t n, num_queries;
  std::cin >> n >> num_queries;
  segtree = new std::vector<std::pair<int32_t, int32_t> >[4 * num_queries];
  std::map<std::pair<int32_t, int32_t>, int32_t> segments;
  for (int32_t q = 0; q < num_queries; q++) {
    int32_t v1, v2;
    std::cin >> v1 >> v2;
    v1--;
    v2--;
    if (v1 > v2) {
      int32_t tmp = v1;
      v1 = v2;
      v2 = tmp;
    }
    auto it = segments.find({v1, v2});
    if (it == segments.end())
      segments[{v1, v2}] = q;
    else {
      add_edge(0, 0, num_queries, it->second, q, {v1, v2});
      segments.erase(it);
    }
  }
  for (auto it = segments.begin(); it != segments.end(); it++)
    add_edge(0, 0, num_queries, it->second, num_queries, it->first);
  Tracker tracker(n);
  get_ans(0, 0, num_queries, tracker);
  return 0;
}
