```go
package main
import (
"fmt"
"sort"
)
type Pair struct {
x, y int
}
type Change struct {
kind string
node int
oldval int
}
var (
n, q int
segtree [][]Pair
parent []int
rank []int
bipar []int
count_bad []int
total_bad int
stackc []Change
active map[[2]int]struct{}
ans []string
)
func min(a, b int) int {
if a < b {
return a
}
return b
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
func update(node, s, e, ql, qr int, edge Pair) {
if ql > e || qr < s {
return
}
if ql <= s && e <= qr {
segtree[node] = append(segtree[node], edge)
return
}
mid := (s + e) / 2
update(2*node, s, mid, ql, qr, edge)
update(2*node+1, mid+1, e, ql, qr, edge)
}
func find(u int) (int, int) {
p := u
par := 0
for p != parent[p] {
par ^= bipar[p]
p = parent[p]
}
return p, par
}
func bool2int(b bool) int {
if b {
return 1
}
return 0
}
func add_edge(u, v int) {
pu, paru := find(u)
pv, parv := find(v)
diff := paru ^ parv
if pu == pv {
if diff == 0 {
old_count := count_bad[pu]
new_count := old_count + 1
if old_count == 0 {
stackc = append(stackc, Change{"total_bad", 0, total_bad})
total_bad++
}
stackc = append(stackc, Change{"count", pu, old_count})
count_bad[pu] = new_count
}
return
}
// union
if rank[pu] > rank[pv] {
pu, pv = pv, pu
paru, parv = parv, paru
}
old_parent := parent[pu]
old_bipar := bipar[pu]
old_rank := rank[pv]
old_count := count_bad[pv]
new_count := count_bad[pu] + count_bad[pv]
old_num := bool2int(count_bad[pu] > 0) + bool2int(old_count > 0)
new_num := bool2int(new_count > 0)
if old_num != new_num {
stackc = append(stackc, Change{"total_bad", 0, total_bad})
total_bad += new_num - old_num
}
stackc = append(stackc, Change{"parent", pu, old_parent})
stackc = append(stackc, Change{"bipar", pu, old_bipar})
stackc = append(stackc, Change{"rank", pv, old_rank})
stackc = append(stackc, Change{"count", pv, old_count})
parent[pu] = pv
bipar[pu] = paru ^ parv ^ 1
if rank[pu] == rank[pv] {
rank[pv]++
}
count_bad[pv] = new_count
}
func dfs(node, start, end int) {
old_stack_size := len(stackc)
var newly_processed [][2]int
for _, e := range segtree[node] {
pair := [2]int{min(e.x, e.y), max(e.x, e.y)}
if _, ok := active[pair]; !ok {
add_edge(e.x, e.y)
active[pair] = struct{}{}
newly_processed = append(newly_processed, pair)
}
}
if start == end {
if total_bad > 0 {
ans[start] = "NO"
} else {
ans[start] = "YES"
}
} else {
mid := (start + end) / 2
dfs(2*node, start, mid)
dfs(2*node+1, mid+1, end)
}
// rollback DSU changes
for len(stackc) > old_stack_size {
ch := stackc[len(stackc)-1]
stackc = stackc[:len(stackc)-1]
switch ch.kind {
case "parent":
parent[ch.node] = ch.oldval
case "bipar":
bipar[ch.node] = ch.oldval
case "rank":
rank[ch.node] = ch.oldval
case "count":
count_bad[ch.node] = ch.oldval
case "total_bad":
total_bad = ch.oldval
}
}
// remove from active
for _, pair := range newly_processed {
delete(active, pair)
}
}
func main() {
fmt.Scan(&n, &q)
segtree = make([][]Pair, 4*q+4)
toggles := make(map[[2]int][]int)
for i := 1; i <= q; i++ {
var x, y int
fmt.Scan(&x, &y)
if x > y {
x, y = y, x
}
pair := [2]int{x, y}
toggles[pair] = append(toggles[pair], i)
}
for key, val := range toggles {
t := val
sort.Ints(t)
for j := 0; j < len(t); j += 2 {
l := t[j]
r := q
if j+1 < len(t) {
r = t[j+1] - 1
}
if l <= r {
update(1, 1, q, l, r, Pair{key[0], key[1]})
}
}
}
parent = make([]int, n+1)
rank = make([]int, n+1)
bipar = make([]int, n+1)
count_bad = make([]int, n+1)
for i := 1; i <= n; i++ {
parent[i] = i
}
total_bad = 0
active = make(map[[2]int]struct{})
ans = make([]string, q+1)
dfs(1, 1, q)
for i := 1; i <= q; i++ {
fmt.Println(ans[i])
}
}
```