using System;
using System.Collections.Generic;

namespace Dijkstra
{
	class MainClass
	{

		enum NODE_STATE {
			YET = 0,
			NOW,
			DONE
		};

		public class PairInfo : IComparable
		{
			public int Item1; // ???????????????
			public int Item2; // ?§??????????????????¢


			public PairInfo(int i1, int i2) {
				Item1 = i1;
				Item2 = i2;
			}

			public int CompareTo(object obj)
			{
				if (obj == null) {
					return 1;
				}

				if (this.GetType () != obj.GetType ()) {
					throw new ArgumentException ("different type of object", "obj");
				}

				return this.Item2.CompareTo (((PairInfo)obj).Item2);
			}
		}

		public class PriorityQueue<T> where T: IComparable
		{
			private IComparer<T> _comparer = null;
			private int _type = 0;

			private T[] _heap;
			private int _sz = 0;

			private int _count = 0;

			/// <summary>
			/// Priority Queue with custom comparer
			/// </summary>
			public PriorityQueue(int maxSize, IComparer<T> comparer)
			{
				_heap = new T[maxSize];
				_comparer = comparer;
			}

			/// <summary>
			/// Priority queue
			/// </summary>
			/// <param name="maxSize">max size</param>
			/// <param name="type">0: asc, 1:desc</param>
			public PriorityQueue(int maxSize, int type = 0)
			{
				_heap = new T[maxSize];
				_type = type;
			}

			private int Compare(T x, T y)
			{
				if (_comparer != null) return _comparer.Compare(x, y);
				return _type == 0 ? x.CompareTo(y) : y.CompareTo(x);
			}

			public void Push(T x)
			{
				_count++;

				//node number
				var i = _sz++;

				while (i > 0)
				{
					//parent node number
					var p = (i - 1) / 2;

					if (Compare(_heap[p], x) <= 0) break;

					_heap[i] = _heap[p];
					i = p;
				}

				_heap[i] = x;
			}

			public T Pop()
			{
				_count--;

				T ret = _heap[0];
				T x = _heap[--_sz];

				int i = 0;
				while (i * 2 + 1 < _sz)
				{
					//children
					int a = i * 2 + 1;
					int b = i * 2 + 2;

					if (b < _sz && Compare(_heap[b], _heap[a]) < 0) a = b;

					if (Compare(_heap[a], x) >= 0) break;

					_heap[i] = _heap[a];
					i = a;
				}

				_heap[i] = x;

				return ret;
			}

			public int Count()
			{
				return _count;
			}

			public T Peek()
			{
				return _heap[0];
			}

			public bool Contains(T x)
			{
				for (int i = 0; i < _sz; i++) if (x.Equals(_heap[i])) return true;
				return false;
			}

			public void Clear()
			{
				while (this.Count() > 0) this.Pop();
			}

			public IEnumerator<T> GetEnumerator()
			{
				var ret = new List<T>();

				while (this.Count() > 0)
				{
					ret.Add(this.Pop());
				}

				foreach (var r in ret)
				{
					this.Push(r);
					yield return r;
				}
			}

			public T[] ToArray()
			{
				T[] array = new T[_sz];
				int i = 0;

				foreach (var r in this)
				{
					array[i++] = r;
				}

				return array;
			}
		}

		//
		// ??°??????????????????
		//
		public class Node
		{
			public const int INFINITY = (1 << 20);


			// ??????????????????ID
			public int nodeId;
			// ?§??????????????????¢
			public int distFromStart;
			// ??????????????¢?´¢??¶???
			public int state;
			// ??£??\??????????????????ID
			public Dictionary <int, int> adjacents;


			public Node (int nid)
			{
				nodeId = nid;
				adjacents = new Dictionary<int, int> ();
			}

			// ?§??????????????????¢?????????????¨????
			public void setDistFromStartAsInf() {
				distFromStart = INFINITY;
			}

			// ??¢?´¢??¶???????????????
			public void setSearchStateYet() {
				state = (int)NODE_STATE.YET;
			}

			//
			// ??£??\??????????????????
			//
			// @param (nid)		????????????????????????ID
			// @param (cost)	????????????????????????????????????
			public void AddAdjacent(int nid, int cost) {
				adjacents.Add (nid, cost);
			}

			//
			// ??????
			//
			public void dumpNode() {
				foreach (var key in adjacents.Keys) {
					Console.WriteLine (string.Format ("{0} => {1} : {2}", nodeId, key, adjacents[key]));
				}
			}

		}

		//
		// ??°???????????????????£??????£??\??¢???
		//
		public class AdjacentTree
		{
			public const int MAX_N = 100000;

			private List <Node> _tree;

			public AdjacentTree(int numNodes)
			{
				_tree = new List<Node> (numNodes);
				for (int i = 0; i < numNodes; ++i) {
					_tree.Add(new Node(i));
				}
			}

			//
			// ??????????????°?????????
			//
			public void AddNodes(int nidFrom, int nidTo, int cost) {
				_tree [nidFrom].AddAdjacent (nidTo, cost);
			}

			//
			// ??????????????¢?´¢???????????????????????????
			//
			public void DijkstraSearch1(int startNodeId) {

				// ??¨?????????????§??????????????????¢???????????§???
				foreach (Node node in _tree) {
					node.setDistFromStartAsInf ();
					node.setSearchStateYet ();
				}

				// ?§????????¨????
				Node curNode = _tree[startNodeId];
				curNode.distFromStart = 0;
				curNode.state = (int)NODE_STATE.NOW;

				// ??¢?´¢????§?
				while (true) {

					// ??£??\?????????????????????????????????????°???????????????????
					int minNid = -1;
					int minCost = Int32.MaxValue;
					for (int i = 0; i < _tree.Count; ++i) {
						if (minCost > _tree [i].distFromStart && 
							_tree [i].state != (int)NODE_STATE.DONE) {
							minNid = i;
							minCost = _tree [i].distFromStart;
						}
					}

					// ??¢?´¢??????
					if (minNid == -1)
						break;

					// ?????????????°??????????????????£??\???????????????????????????????¨????
					Node minNode = _tree [minNid];
					minNode.distFromStart = minCost;
					minNode.state = (int)NODE_STATE.DONE;
					foreach (int adjNid in minNode.adjacents.Keys) {
						Node adjNode = _tree [adjNid];
						if (adjNode.state != (int)NODE_STATE.DONE &&
							(minNode.distFromStart + minNode.adjacents[adjNid]) < adjNode.distFromStart) {

							adjNode.distFromStart = minNode.distFromStart + minNode.adjacents [adjNid];
							adjNode.state = (int)NODE_STATE.NOW;

						}
					}

				}

				// ???????????¢?????????
				foreach (Node node in _tree) {
					Console.WriteLine (string.Format ("{0} {1}", node.nodeId, node.distFromStart));
				}

			}

			//
			// ??????????????¢?´¢???????????????????????????
			//
			public void DijkstraSearch2(int startNodeId) {

				// ??¨?????????????§??????????????????¢???????????§???
				foreach (Node node in _tree) {
					node.setDistFromStartAsInf ();
					node.setSearchStateYet ();
				}

				// ?§????????¨????
				Node startNode = _tree[startNodeId];
				startNode.distFromStart = 0;
				startNode.state = (int)NODE_STATE.NOW;

				// ????????????????????\???????????????
				PriorityQueue<PairInfo> PQ = new PriorityQueue <PairInfo> (MAX_N, 1);
				PQ.Push (new PairInfo (0, 0));

				while (PQ.Count () > 0) {
					PairInfo top = PQ.Pop ();
					int nid = top.Item1;

					Node node = _tree [nid];

					node.state = (int)NODE_STATE.DONE;
					if (node.distFromStart < top.Item2 * (-1))
						continue;

					foreach (int adjNid in node.adjacents.Keys) {
						Node adjNode = _tree [adjNid];
						if (adjNode.state == (int)NODE_STATE.DONE)
							continue;
						if (adjNode.distFromStart > node.distFromStart + node.adjacents [adjNid]) {
							try {
								adjNode.distFromStart = node.distFromStart + node.adjacents [adjNid];
								PQ.Push (new PairInfo (adjNid, adjNode.distFromStart * (-1)));
								adjNode.state = (int)NODE_STATE.NOW;
							}
							catch (System.IndexOutOfRangeException ex) {
								Console.WriteLine ("adjNid: " + adjNid);
								Console.WriteLine ("PQ Count: " + PQ.Count());
								Console.WriteLine (ex);
							}
						}
					}

				}


				// ???????????¢?????????
				foreach (Node node in _tree) {
					Console.WriteLine (string.Format ("{0} {1}", node.nodeId, node.distFromStart));
				}

			}

			//
			// ??????
			//
			public void dumpTree() {
				foreach (Node node in _tree) {
					node.dumpNode ();
				}
			}

		}

		public static void Main (string[] args)
		{

			// ??°???????????????
			int n = int.Parse(Console.ReadLine());
			AdjacentTree adjTree = new AdjacentTree (n);

			// ?????????????????????
			string readLine = null;
			for (int i = 0; i < n; ++i) {
				
				readLine = Console.ReadLine ();
				string[] splitedNums = readLine.Split (' ');
				int k = int.Parse (splitedNums[1]);

				// ??£??\????????¨?????????????????????
				for (int j = 0; j < k; ++j) {
					int v = int.Parse (splitedNums[2 + j * 2]);
					int c = int.Parse (splitedNums[2 + j * 2 + 1]);
					adjTree.AddNodes (i, v, c);
				}
			}

			// ??????????????¢?´¢
			adjTree.DijkstraSearch2(0);

		}
	}
}

Measured memory_bytes: 47940