Problem:
Score: 400 points

Problem Statement

There is a cave.

The cave has N rooms and M passages. The rooms are numbered 1 to N, and the passages are numbered 1 to M. Passage i connects Room A_i and Room B_i bidirectionally. One can travel between any two rooms by traversing passages. Room 1 is a special room with an entrance from the outside.

It is dark in the cave, so we have decided to place a signpost in each room except Room 1. The signpost in each room will point to one of the rooms directly connected to that room with a passage.

Since it is dangerous in the cave, our objective is to satisfy the condition below for each room except Room 1.

If you start in that room and repeatedly move to the room indicated by the signpost in the room you are in, you will reach Room 1 after traversing the minimum number of passages possible.

Determine whether there is a way to place signposts satisfying our objective, and print one such way if it exists.

Constraints

All values in input are integers.

2 \leq N \leq 10^5

1 \leq M \leq 2 \times 10^5

1 \leq A_i, B_i \leq N\ (1 \leq i \leq M)

A_i \neq B_i\ (1 \leq i \leq M)

One can travel between any two rooms by traversing passages.

Input

Input is given from Standard Input in the following format:

N M
A_1 B_1
:
A_M B_M

Output

If there is no way to place signposts satisfying the objective, print No.

Otherwise, print N lines. The first line should contain Yes, and the i-th line (2 \leq i \leq N) should contain the integer representing the room indicated by the signpost in Room i.

Sample Input 1

4 4
1 2
2 3
3 4
4 2

Sample Output 1

Yes
1
2
2

If we place the signposts as described in the sample output, the following happens:

Starting in Room 2, you will reach Room 1 after traversing one passage: (2) \to 1. This is the minimum number of passages possible.

Starting in Room 3, you will reach Room 1 after traversing two passages: (3) \to 2 \to 1. This is the minimum number of passages possible.

Starting in Room 4, you will reach Room 1 after traversing two passages: (4) \to 2 \to 1. This is the minimum number of passages possible.

Thus, the objective is satisfied.

Sample Input 2

6 9
3 4
6 1
2 4
5 3
4 6
1 5
6 2
4 5
5 6

Sample Output 2

Yes
6
5
5
1
1

If there are multiple solutions, any of them will be accepted.

Solution in Java (OpenJDK 11.0.6) (judge verdict: Time Limit Exceeded)


import java.util.*;
import java.lang.Integer;

public class Main {

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		int m = sc.nextInt();
		SparseWeightedGraph sparseGraph = new SparseWeightedGraph(n, false);
		for (int i = 0; i < m; i++) {
			int a = sc.nextInt();
			int b = sc.nextInt();
			sparseGraph.addEdge(a-1,b-1);
		}
		Dijkstra doubleDijkstra = new Dijkstra(sparseGraph, 0);
		for (int i = 2; i <= n; i++) {
			if (doubleDijkstra.hasPathTo(i-1)==false) {
				System.out.println("No");
				return;
			}
		}
		System.out.println("Yes");
		for (int i = 2; i <= n; i++) {
			System.out.println(doubleDijkstra.shortestPathReverse(i-1).v()+1);
		}
	}

}

class Dijkstra {
	private SparseWeightedGraph graph;
	private int s;
	private boolean[] marked;
	private Integer[] distTo;
	private Edge[] from;

	Dijkstra(SparseWeightedGraph graph, int s) {
		this.graph = graph;
		this.s = s;
		this.distTo = new Integer[graph.V()];
		this.marked = new boolean[graph.V()];
		this.from = new Edge[graph.V()];
		for (int i = 0; i < graph.V(); i++) {
			distTo[i] = 0;
			marked[i] = false;
			from[i] = null;
		}
		IndexMinHeap<Integer> ipq = new IndexMinHeap<>(graph.V());
		// Dijkstra
		distTo[s] = 0;
		from[s] = new Edge(s, s);
		marked[s] = true;
		ipq.insert(s, distTo[s]);
		while (!ipq.isEmpty()) {
			int v = ipq.extractMinIndex();
			marked[v] = true;
			// relaxation
			graph.adj(v).forEach(item -> {
				int w = item.other(v);
				if (!marked[w]) {
					if (from[w] == null || distTo[v].intValue() + 1 < distTo[w].intValue()) {
						distTo[w] = (distTo[v].intValue() + 1);
						from[w] = item;
						if (ipq.contain(w)) {
							ipq.change(w, distTo[w]);
						} else {
							ipq.insert(w, distTo[w]);
						}
					}
				}
			});
		}
	}

	public boolean hasPathTo(int w) {
		assert w >= 0 && w < graph.V();
		return marked[w];
	}

	// find the shortest path from s to w
	Edge shortestPathReverse(int w) {
		Edge edge = from[w];
		return edge;
	}

}

class Edge {
	private int a, b;

	Edge(int v, int w) {
		this.a = v;
		this.b = w;
	}

	public int v() {
		return a;
	}

	public int w() {
		return b;
	}

	public int other(int x) {
		assert (x == a) || (x == b);
		return x == a ? b : a;
	}
}

// 最小索引堆
class IndexMinHeap<Item extends Comparable> {

	protected Item[] data;      // 最小索引堆中的数据
	protected int[] indexes;    // 最小索引堆中的索引, indexes[x] = i 表示索引i在x的位置
	protected int[] reverse;    // 最小索引堆中的反向索引, reverse[i] = x 表示索引i在x的位置
	protected int count;
	protected int capacity;

	// 构造函数, 构造一个空堆, 可容纳capacity个元素
	public IndexMinHeap(int capacity) {
		data = (Item[]) new Comparable[capacity + 1];
		indexes = new int[capacity + 1];
		reverse = new int[capacity + 1];
		for (int i = 0; i <= capacity; i++)
			reverse[i] = 0;

		count = 0;
		this.capacity = capacity;
	}

	// 返回索引堆中的元素个数
	public int size() {
		return count;
	}

	// 返回一个布尔值, 表示索引堆中是否为空
	public boolean isEmpty() {
		return count == 0;
	}

	// 向最小索引堆中插入一个新的元素, 新元素的索引为i, 元素为item
	// 传入的i对用户而言,是从0索引的
	public void insert(int i, Item item) {

		assert count + 1 <= capacity;
		assert i + 1 >= 1 && i + 1 <= capacity;

		// 再插入一个新元素前,还需要保证索引i所在的位置是没有元素的。
		assert !contain(i);

		i += 1;
		data[i] = item;
		indexes[count + 1] = i;
		reverse[i] = count + 1;
		count++;

		shiftUp(count);
	}

	// 从最小索引堆中取出堆顶元素, 即索引堆中所存储的最小数据
	public Item extractMin() {
		assert count > 0;

		Item ret = data[indexes[1]];
		swapIndexes(1, count);
		reverse[indexes[count]] = 0;
		count--;
		shiftDown(1);

		return ret;
	}

	// 从最小索引堆中取出堆顶元素的索引
	public int extractMinIndex() {
		assert count > 0;

		int ret = indexes[1] - 1;
		swapIndexes(1, count);
		reverse[indexes[count]] = 0;
		count--;
		shiftDown(1);

		return ret;
	}

	// 获取最小索引堆中的堆顶元素
	public Item getMin() {
		assert count > 0;
		return data[indexes[1]];
	}

	// 获取最小索引堆中的堆顶元素的索引
	public int getMinIndex() {
		assert count > 0;
		return indexes[1] - 1;
	}

	// 看索引i所在的位置是否存在元素
	boolean contain(int i) {
		assert i + 1 >= 1 && i + 1 <= capacity;
		return reverse[i + 1] != 0;
	}

	// 获取最小索引堆中索引为i的元素
	public Item getItem(int i) {
		assert contain(i);
		return data[i + 1];
	}

	// 将最小索引堆中索引为i的元素修改为newItem
	public void change(int i, Item newItem) {

		assert contain(i);

		i += 1;
		data[i] = newItem;

		// 有了 reverse 之后,
		// 我们可以非常简单的通过reverse直接定位索引i在indexes中的位置
		shiftUp(reverse[i]);
		shiftDown(reverse[i]);
	}

	// 交换索引堆中的索引i和j
	// 由于有了反向索引reverse数组，
	// indexes数组发生改变以后， 相应的就需要维护reverse数组
	private void swapIndexes(int i, int j) {
		int t = indexes[i];
		indexes[i] = indexes[j];
		indexes[j] = t;

		reverse[indexes[i]] = i;
		reverse[indexes[j]] = j;
	}

	//********************
	//* 最小索引堆核心辅助函数
	//********************

	// 索引堆中, 数据之间的比较根据data的大小进行比较, 但实际操作的是索引
	private void shiftUp(int k) {

		while (k > 1 && data[indexes[k / 2]].compareTo(data[indexes[k]]) > 0) {
			swapIndexes(k, k / 2);
			k /= 2;
		}
	}

	// 索引堆中, 数据之间的比较根据data的大小进行比较, 但实际操作的是索引
	private void shiftDown(int k) {

		while (2 * k <= count) {
			int j = 2 * k;
			if (j + 1 <= count && data[indexes[j + 1]].compareTo(data[indexes[j]]) < 0)
				j++;

			if (data[indexes[k]].compareTo(data[indexes[j]]) <= 0)
				break;

			swapIndexes(k, j);
			k = j;
		}
	}
}

class SparseWeightedGraph{
	private int n, m;
	private boolean directed;
	private ArrayList<ArrayList<Edge>> g;

	SparseWeightedGraph(int n, boolean directed) {
		this.n = n;
		this.m = 0;
		this.g = new ArrayList<>();
		this.directed = directed;
		for (int i = 0; i < n; i++) {
			g.add(i, new ArrayList<>());
		}
	}

	private void checkOutOfRange(int v) {
		if (v > n || v < 0) {
			throw new IllegalArgumentException("v is out of range");
		}
	}

	public int V() {
		return this.n;
	}

	public int E() {
		return this.m;
	}

	public void addEdge(Edge edge) {
		this.addEdge(edge.v(), edge.w());
	}

	public void addEdge(int v, int w) {
		this.checkOutOfRange(v);
		this.checkOutOfRange(w);

		if (this.hasEdge(v, w)) {
			return;
		}
		g.get(v).add(new Edge(v, w));
		if (v != w && !directed) {
			g.get(w).add(new Edge(w, v));
		}
		m++;
	}

	public boolean hasEdge(int v, int w) {
		this.checkOutOfRange(v);
		this.checkOutOfRange(w);
		for (int j = 0; j < g.get(v).size(); j++) {
			if (g.get(v).get(j).other(v) == w) {
				return true;
			}
		}
		return false;
	}

	public Iterable<Edge> adj(int v) {
		this.checkOutOfRange(v);
		return g.get(v);
	}
}