← Home
package main

import (
	"bufio"
	"fmt"
	"os"
)

const maxN = 1000005

var (
	head    = make([]int, maxN)
	to      = make([]int, 2*maxN)
	nextArr = make([]int, 2*maxN)
	parent  = make([]int, maxN)
	depth   = make([]int, maxN)
	color   = make([]int, maxN)
	C_cov   = make([]int, maxN)
	NC_cov  = make([]int, maxN)
	visited = make([]bool, maxN)
	flip    = make([]bool, maxN)
	order   = make([]int, 0, maxN)
	stack   = make([]State, 0, maxN)
)

type State struct {
	u, edge int
}

var reader *bufio.Reader
var out *bufio.Writer

func readInt() int {
	res := 0
	b, err := reader.ReadByte()
	if err != nil {
		return 0
	}
	for b < '0' || b > '9' {
		b, err = reader.ReadByte()
		if err != nil {
			return 0
		}
	}
	for '0' <= b && b <= '9' {
		res = res*10 + int(b-'0')
		b, err = reader.ReadByte()
		if err != nil {
			break
		}
	}
	return res
}

func main() {
	reader = bufio.NewReader(os.Stdin)
	out = bufio.NewWriter(os.Stdout)
	defer out.Flush()

	t := readInt()
	for tc := 0; tc < t; tc++ {
		n := readInt()
		m := readInt()

		for i := 1; i <= n; i++ {
			head[i] = -1
			visited[i] = false
			flip[i] = false
			C_cov[i] = 0
			NC_cov[i] = 0
		}

		edgeIdx := 0
		for i := 0; i < m; i++ {
			u := readInt()
			v := readInt()

			to[edgeIdx] = v
			nextArr[edgeIdx] = head[u]
			head[u] = edgeIdx
			edgeIdx++

			to[edgeIdx] = u
			nextArr[edgeIdx] = head[v]
			head[v] = edgeIdx
			edgeIdx++
		}

		order = order[:0]
		stack = stack[:0]

		stack = append(stack, State{1, head[1]})
		visited[1] = true
		parent[1] = 0
		depth[1] = 0
		color[1] = 0

		C := 0
		var conflict_edge [2]int

		for len(stack) > 0 {
			curr := &stack[len(stack)-1]
			u := curr.u
			e := curr.edge

			if e != -1 {
				v := to[e]
				curr.edge = nextArr[e]

				if !visited[v] {
					visited[v] = true
					parent[v] = u
					depth[v] = depth[u] + 1
					color[v] = 1 - color[u]
					stack = append(stack, State{v, head[v]})
				} else if v != parent[u] && depth[v] < depth[u] {
					if color[u] == color[v] {
						C++
						C_cov[u]++
						C_cov[v]--
						conflict_edge = [2]int{u, v}
					} else {
						NC_cov[u]++
						NC_cov[v]--
					}
				}
			} else {
				order = append(order, u)
				stack = stack[:len(stack)-1]
			}
		}

		if C == 0 {
			fmt.Fprintln(out, "YES")
			for i := 1; i <= n; i++ {
				if color[i] == 1 {
					out.WriteByte('1')
				} else {
					out.WriteByte('0')
				}
			}
			out.WriteByte('\n')
		} else if C == 1 {
			fmt.Fprintln(out, "YES")
			c := color[conflict_edge[0]]
			for i := 1; i <= n; i++ {
				if color[i] == c {
					out.WriteByte('1')
				} else {
					out.WriteByte('0')
				}
			}
			out.WriteByte('\n')
		} else {
			for i := 0; i < n; i++ {
				u := order[i]
				if parent[u] != 0 {
					C_cov[parent[u]] += C_cov[u]
					NC_cov[parent[u]] += NC_cov[u]
				}
			}

			found := -1
			for i := 1; i <= n; i++ {
				if parent[i] != 0 && C_cov[i] == C && NC_cov[i] == 0 {
					found = i
					break
				}
			}

			if found != -1 {
				flip[found] = true
				for i := n - 1; i >= 0; i-- {
					u := order[i]
					if parent[u] != 0 && flip[parent[u]] {
						flip[u] = true
					}
				}
				for i := 1; i <= n; i++ {
					if flip[i] {
						color[i] = 1 - color[i]
					}
				}

				fmt.Fprintln(out, "YES")
				c := color[found]
				for i := 1; i <= n; i++ {
					if color[i] == c {
						out.WriteByte('1')
					} else {
						out.WriteByte('0')
					}
				}
				out.WriteByte('\n')
			} else {
				fmt.Fprintln(out, "NO")
			}
		}
	}
}