Go: package main

import (
	"bufio"
	"container/heap"
	"fmt"
	"os"
	"strconv"
)

const NIL = -1

type Node struct {
	id     int
	weight int
}

func init() {
	sc.Split(bufio.ScanWords)
}

type NodeHeap []Node

func (h NodeHeap) Len() int           { return len(h) }
func (h NodeHeap) Less(i, j int) bool { return h[i].weight < h[j].weight }
func (h NodeHeap) Swap(i, j int)      { h[i], h[j] = h[j], h[i] }

func (h *NodeHeap) Push(x interface{}) {
	*h = append(*h, x.(Node))
}

func (h *NodeHeap) Pop() interface{} {
	old := *h
	n := len(old)
	x := old[n-1]
	*h = old[0 : n-1]
	return x
}

var sc = bufio.NewScanner(os.Stdin)

func scanInt() int {
	num, _ := strconv.Atoi(scanString())
	return num
}

func scanString() string {
	sc.Scan()
	return sc.Text()
}

func init() {
	sc.Split(bufio.ScanWords)
}

func main() {
	n := scanInt()

	route := make([][]Node, n)
	weight := make([]int, n)
	for i := 0; i < n; i++ {
		weight[i] = NIL
	}

	for i := 0; i < n; i++ {
		u := scanInt()
		k := scanInt()
		route[i] = make([]Node, k)
		for j := 0; j < k; j++ {
			route[u][j] = Node{id: scanInt(), weight: scanInt()}
		}
	}

	start := Node{id: 0, weight: 0}
	h := &NodeHeap{start}
	heap.Init(h)

	for h.Len() > 0 {
		node := heap.Pop(h).(Node)
		if weight[node.id] != NIL {
			continue
		}
		weight[node.id] = node.weight

		for _, nextNode := range route[node.id] {
			if weight[nextNode.id] != NIL {
				continue
			}
			nextNode.weight += node.weight
			heap.Push(h, nextNode)
		}
	}

	for i, w := range weight {
		fmt.Println(i, w)
	}
}

C++: #include <bits/stdc++.h>
 
using namespace std;

namespace dijkstra_n {
template<class W>
struct Edge {
	using type = Edge<W>;
	int to;
	W w;
	template<class... Args> Edge(int t, Args... args) : to(t), w(args...) {}
	inline bool operator<(const Edge& rhs) const { return w < rhs.w; }
	inline bool operator>(const type& rhs) const { return rhs < *this; }
	inline bool operator>=(const type& rhs) const { return !(*this < rhs); }
	inline bool operator<=(const type& rhs) const { return !(rhs < *this); }
	inline bool operator==(const type& rhs) const { return !(*this < rhs) && !(rhs < *this); }
	inline bool operator!=(const type& rhs) const { return (*this < rhs) || (rhs < *this); }
};
template<class W>
struct Edges : private vector<vector<Edge<W>>> {
	using type = vector<vector<Edge<W>>>;
	template<class... Args> Edges(Args... args) : type(args...) {}
	template<class... Args> void add_edge(int u, int v, Args... args) {
		(*this)[u].emplace_back(v, args...);
	}
	using type::begin; using type::end; using type::rbegin; using type::rend;
	using type::cbegin; using type::cend; using type::crbegin; using type::crend;
	using type::size; using type::operator[]; using type::at; using type::back; using type::front;
	using type::reserve; using type::resize; using type::assign; using type::shrink_to_fit;
	using type::clear; using type::erase; using type::insert; using type::swap; 
	using type::push_back; using type::pop_back; using type::emplace_back; using type::empty;
};
template<class W>
struct Graph {
	const int sz;
	Edges<W> e;
	Graph(int n) : sz(n), e(sz) {}
	template<class... Args> void add_edge(int u, int v, Args... args) {
		e.add_edge(u, v, args...);
	}
	int size() {
		return sz;
	}
};
template<class W, class T = W>
struct Graph_D : public Graph<W> {
	vector<T> dist;
	Graph_D(int n) : Graph<W>(n), dist(n) {}
};
template<class W, class T>
void Dijkstra(Graph_D<W, T>& g, int start, T INF_COST) {
	auto& dist = g.dist;
	auto& e = g.e;
	for (auto& ww : dist) ww = INF_COST;
	using Q_T = pair<T, int>;
	priority_queue<Q_T, vector<Q_T>, greater<>> q;
	q.emplace(0, start);
	while (!q.empty()) {
		auto a = q.top();
		q.pop();
		if (a.first >= dist[a.second]) continue;
		dist[a.second] = a.first;
	for (auto& p : e[a.second]) {
			if (p.w == INF_COST) continue;
			if (a.first + p.w < dist[p.to]) q.emplace(a.first + p.w, p.to);
		}
	}
}
}
using dijkstra_n::Dijkstra;
template<class T, class U = T> using graph = dijkstra_n::Graph_D<T, U>;

int main() {
    int n; cin >> n;
    graph<int> g(n);
    for (int i = 0; i < n; i++) {
        int v, k; cin >> v >> k;
        while (k--) {
            int u, c; cin >> u >> c;
            g.add_edge(v, u, c);
        }
    }
    Dijkstra(g, 0, INT_MAX);
    for (int i = 0; i < n; i++) {
        cout << i << " " << g.dist[i] << endl;
    }
}

C++: #include <cassert>
#include <climits>
#include <algorithm>
#include <iostream>
#include <vector>
#include <list>
#include <string>


class TVertex;
struct TPath
{
    int Cost;
    TVertex* Target;
    TPath(TVertex* ATarget, int ACost)
     : Target(ATarget), Cost(ACost) {}
};
bool Compare(const TPath& Left, const TPath& Right)
{
    if(Left.Cost  < 0) return false;
    if(Right.Cost < 0) return true;
    return Left.Cost < Right.Cost;
}
class TVertex
{
    int FIndex;
    std::vector<TPath> FList;
    int FDistance;

public:
    TVertex(int Index)
     : FIndex(Index), FDistance(INT_MAX)
    {}
    void Reserve(int Size)
    {
        FList.reserve(Size);
    }
    void AddPath(const TPath& Path)
    {
        FList.push_back(Path);
    }
    void SortPath()
    {
        std::sort(FList.begin(), FList.end(), Compare);
    }
    void PrintDistance(std::ostream& out)const
    {
        out << FIndex << " " << FDistance << std::endl;
    }
    void BreadthFirstSearch(int Distance)
    {
        if(FDistance <= Distance) return;
        FDistance = Distance;
        for(std::vector<TPath>::iterator It = FList.begin(); It != FList.end(); ++It){
            It->Target->BreadthFirstSearch(Distance + It->Cost);
        }
    }
};
class TGraph
{
    std::vector<TVertex*> FTable;
    void Init(int n)
    {
        assert(n > 0);
        FTable.resize(n);
        for(int i = 0; i < n; ++i){
            FTable[i] = new TVertex(i);
        }
    }
public:
    TGraph(int n)
    {
        Init(n);
    }
    
    void SetupVertex(std::istream& in)
    {
        int Index;
        in >> Index;
        assert(Index >= 0);
        assert(Index < FTable.size());
        int k;
        in >> k;
        FTable[Index]->Reserve(k);
        for(int i = 0; i < k; ++i){
            int v, c;
            in >> v >> c;
            FTable[Index]->AddPath(TPath(FTable[v], c));
        }
        FTable[Index]->SortPath();
    }
    void BreadthFirstSearch()
    {
        FTable[0]->BreadthFirstSearch(0);
    }
    void PrintDistance(std::ostream& out)
    {
        for(int i = 0; i < FTable.size(); ++i){
            FTable[i]->PrintDistance(out);
        }
    }
};

int main()
{
    std::cin.tie(0);
    std::ios::sync_with_stdio(false);
    int n;
    std::cin >> n;
    TGraph Graph(n);
    for(int i = 0; i < n; ++i){
        Graph.SetupVertex(std::cin);
    }
    Graph.BreadthFirstSearch();
    Graph.PrintDistance(std::cout);
    return 0;
    
}