Problem:
船旅

問題

JOI国には，n 島の島があり，各島には 1 から n までの番号が付けられている．現在，JOI国では各島の間を結ぶ航路網の整備が進んでいる．

あなたは，船舶の切符を扱っているチケットセンターに勤務している．JOI国には船舶を使って，できる限り安価に，島と島の間を旅行したいと考えている人が沢山おり，彼らは，出発地と目的地を注文票に記入して，あなたのところに送ってくる．

あなたの仕事は，客から注文票を受け取ったらすぐに，いくつかの船舶を乗り継いで，出発地と目的地を結ぶ航路の中で，もっとも安価な運賃を計算し，客に伝えることである．
ただし，旅程によっては，船舶を使って旅行することが出来ない場合もある．そのときは『船舶を使って旅行することが出来ない』と客に伝える必要がある．また，JOI国では，島と島の間を結ぶ新しい船舶が，次々と運航を開始しており，あなたには，その情報が随時伝えられる．客に返事をする際には，最新の情報に留意しなければならない．

入力として，客の注文票や新たに運航を開始した船舶の運航情報が与えられたときに，客への返事を求めるプログラムを作成せよ．

なお，入力例１と出力例１に対する実行状況を，図１として図示している．

入力

入力は複数のデータセットからなる．各データセットは以下の形式で与えられる．

入力の 1 行目には2つの整数 n, k (1 ≤ n ≤ 100, 1 ≤ k ≤ 5000) が書かれている．これは，島の数が n 島で，入力が k + 1 行からなることを表す．
i + 1 行目 (1 ≤ i ≤ k) には， 3 個または 4 個の整数が空白を区切りとして書かれている．

最初の数字が 0 のとき，この行は客の注文票を表す．

この行には3個の整数 0, a, b (1 ≤ a ≤ n, 1 ≤ b ≤ n, a ≠ b) が空白を区切りとして書かれている．
これは，客が，島 a を出発地とし島 b を目的地とするような注文票を送ってきたことを表す．

最初の数字が 1 のとき，この行は新たに運航を開始した船舶の運航情報を表す．

この行には 4 個の整数 1, c, d, e (1 ≤ c ≤ n, 1 ≤ d ≤ n, c ≠ d, 1 ≤ e ≤ 1000000) が書かれている．

これは島 c と島 d を往復する船舶が新たに運航を開始し，この船舶の島 c から島 d への運賃と，島 d から島 c への運賃が，共に e であることを表す．

この行以降の注文票に対しては，この船舶も考慮して返事をしなければならない．

最初の段階では，船舶は一隻も運航していないものとする．入力のうち，船舶の運航情報を表す行は 1000 行以下である．また，島と島の間に，複数の船舶が運航することがあることに注意せよ．

n, k がともに 0 のとき入力の終了を示す. データセットの数は 5 を超えない．

出力

データセットごとに以下の形式で出力する．

入力のうち，注文票を表す行の数を m とおく．
各データセットの出力は m 行からなり， i 行目(1 ≤ i ≤ m)には， i 番目の注文票に対する返事を表す整数を書く．
すなわち， i 番目の注文票の出発地と目的地の間を，いくつかの船舶を乗り継いで旅行することが可能ならば，その運賃の合計の最小値を書く．旅行することが不可能ならば，-1 を出力する．

入出力例

入力例

3 8
1 3 1 10
0 2 3
1 2 3 20
1 1 2 5
0 3 2
1 1 3 7
1 2 1 9
0 2 3
5 16
1 1 2 343750
1 1 3 3343
1 1 4 347392
1 1 5 5497
1 2 3 123394
1 2 4 545492
1 2 5 458
1 3 4 343983
1 3 5 843468
1 4 5 15934
0 2 1
0 4 1
0 3 2
0 4 2
0 4 3
0 5 3
0 0

出力例

-1
15
12
5955
21431
9298
16392
24774
8840

上記問題文と自動審判に使われるデータは、情報オリンピック日本委員会が作成し公開している問題文と採点用テストデータです。

Solution in Ruby (judge verdict: Time Limit Exceeded)

module Graph
	require 'set'
	def add_node(label = nil)
		Node.new(label)
	end

	def add_edge(u, v, label = nil)
		e = Edge.new(u, v, label)
		u.outgoings << e
		v.incomings << e
		e
	end
	
	def del_edge(e)
		u, v = e.from, e.to
		u.outgoings.delete(e)
		v.incomings.delete(e)
		e
	end

	class Node
		def initialize(label)
			@label = label
			@outgoings = Set.new
			@incomings = Set.new
		end

		def to_nodes
			@outgoings.map(&:to)
		end

		def from_nodes
			@incomings.map(&:from)
		end

		def to_s
			@label
		end
		
		attr_accessor :incomings, :outgoings
		attr_reader :label
	end

	class Edge
		def initialize(u, v, label = nil)
			@from = u	
			@to = v
			@label = label
		end
		attr_reader :from, :to, :label
	end

	def get_path_bfs(s, t)
		path_edge = {}
		reached = Set[s]
		queue = [s]
		while !queue.empty? 
			u = queue.shift
			u.outgoings.each{|e|
				v = e.to
				next if reached.include?(v)	
				reached << v
				queue << v
				path_edge[v] = e

				if v == t
					path = []
					while e = path_edge[v]
						path.unshift e
						v = e.from
					end
					return path
				end
			}
		end	
		return nil
	end

	def get_path_dfs(s, t, reached = Set.new)
		reached << s	
		s.outgoings.each{|e|
			v = e.to
			next if reached.include?(v)
			return [e] if v == t
			
			path = get_path_dfs(v, t, reached) 
			return [e] + path if path
		}
		nil
	end

	def layers_from(start)
		reached = Set[*start]
		layers = [start]

		loop {
			layers << []
			layers[-2].each{|u|
				u.to_nodes.each{|v|
					next if reached.include?(v)
					reached << v
					layers[-1] << v
				}
			}	

			if layers[-1].empty?
				layers.pop
				return layers
			end
		}
	end

	def reachable_from(s, reached = Set.new, root = true)
		reached << s	
		s.outgoings.each{|e|
			v = e.to
			next if reached.include?(v)
			reachable_from(v, reached, false) 
		}
		root ? reached : nil
	end

	def dijkstra(s, t = nil)
		dist = {}
		h = Heap.new
		h.add(s, 0)
		reached = Set[s]
		until h.size == 0
			u, key = h.del_min
			return key if u == t
			dist[u] = key
			u.outgoings.each{|e|
				v = e.to
				d = dist[u] + e.label
				if reached.include?(v)
					h.update_key(v, d)
				else
					h.add(v, d)
					reached << v
				end
			}
		end
		t ? nil : dist
	end
end

class Heap
	require 'forwardable'
	extend Forwardable

	def initialize
		@array = []
		@index = {}
	end

	def add(obj, key)
		@array << [obj, key]
		@index[obj] = @array.size - 1
		lift_up(@array.size - 1)
	end

	def swap(i, j)
		u = @array[i]
		v = @array[j]
		@index[u[0]], @index[v[0]] = j, i
		@array[i], @array[j] = v, u
	end

	def lift_up(i)
		return if i == 0
		j = (i - 1) / 2
		if @array[i][1] < @array[j][1]
			swap(i, j)
			lift_up(j)
		end
	end

	def del_min
		raise "heap is empty!" if empty?
		min = @array[0]
		if size > 1
			swap(0, @array.size-1)
			@array.pop
			lift_down(0)
		else
			@array.pop
		end
		@index.delete(min[0])
		min
	end

	def inc_key(obj, diff)
		i = @index[obj]
		@array[i][1] += diff
		lift_down(i)
	end

	def dec_key(obj, diff)
		i = @index[obj]
		@array[i][1] -= diff
		lift_up(i)
	end

	def update_key(obj, new_key)
		i = @index[obj]
		return unless i
		return if new_key >= @array[i][1]
		@array[i][1] = new_key
		lift_up(i)
	end

	def min_obj
		@array[0][0]
	end

	def min_key
		@array[0][1]
	end

	def lift_down(i)
		j = 2 * i + 1
		k = j + 1
		if k >= size
			return if j >= size
			if @array[i][1] > @array[j][1]
				swap(i, j)
				lift_down(j)
			end
		else
			l = (@array[j][1] < @array[k][1] ? j : k)
			if @array[i][1] > @array[l][1]
				swap(i, l)
				lift_down(l)
			end
		end
	end

	def_delegators :@array, :empty?, :size
end

include Graph

loop {
	n, k = gets.split.map &:to_i
	break if n == 0
	nodes = (1..n).map{ add_node }	

	k.times {
		query, i, j, c = gets.split.map &:to_i
		u = nodes[i-1]
		v = nodes[j-1]
		if query == 1
			add_edge(u, v, c)
			add_edge(v, u, c)
		else
			p dijkstra(u, v) || -1
		end
	}
}