Go: // Warshall–Floyd Algorithm

package main

import (
	"bufio"
	"os"
	"strings"
	"strconv"
	"fmt"
)

var scanner = bufio.NewScanner(os.Stdin)

const INF = 0x7FFFFFFF

func main() {
	for scanner.Scan() {
		buf := strings.Split(scanner.Text(), " ")
		n, _ := strconv.Atoi(buf[0])
		m, _ := strconv.Atoi(buf[1])
		if n == 0 && m == 0 {
			break
		}
		c_matrix := make([][]int, m)
		for i := range c_matrix {
			c_matrix[i] = make([]int, m)
		}
		t_matrix := make([][]int, m)
		for i := range t_matrix {
			t_matrix[i] = make([]int, m)
		}
		for i := 0; i < n; i++ {
			scanner.Scan()
			buf_ := strings.Split(scanner.Text(), " ")
			a, _ := strconv.Atoi(buf_[0])
			b, _ := strconv.Atoi(buf_[1])
			c, _ := strconv.Atoi(buf_[2])
			t, _ := strconv.Atoi(buf_[3])
			c_matrix[a-1][b-1] = c
			t_matrix[a-1][b-1] = t
		}
		c_dist := make([][]int, m)
		c_prev := make([][]int, m)
		t_dist := make([][]int, m)
		t_prev := make([][]int, m)
		for i := 0; i < m; i++ {
			c_dist[i] = make([]int, m)
			c_prev[i] = make([]int, m)
			t_dist[i] = make([]int, m)
			t_prev[i] = make([]int, m)
		}
		for i := 0; i < m; i++ {
			for j := 0; j < m; j++ {
				if c_matrix[i][j] == 0{
					c_dist[i][j] = INF
				} else {
					c_dist[i][j] = c_matrix[i][j]
				}
				if c_matrix[i][j] == 0{
					c_prev[i][j] = -1
				} else {
					c_prev[i][j] = i
				}
				if t_matrix[i][j] == 0{
					t_dist[i][j] = INF
				} else {
					t_dist[i][j] = t_matrix[i][j]
				}
				if t_matrix[i][j] == 0{
					t_prev[i][j] = -1
				} else {
					t_prev[i][j] = i
				}
			}
			c_dist[i][i] = 0
			t_dist[i][i] = 0
		}
		for k := 0; k < m; k++ {
			for i := 0; i < m; i++ {
				for j := 0; j < m; j++ {
					c_newlen := c_dist[i][k] + c_dist[k][j]
					t_newlen := t_dist[i][k] + t_dist[k][j]
					if c_newlen < c_dist[i][j] {
						c_dist[i][j] = c_newlen
						c_prev[i][j] = c_prev[k][j]
					}
					if t_newlen < t_dist[i][j] {
						t_dist[i][j] = t_newlen
						t_prev[i][j] = t_prev[k][j]
					}
				}
			}
		}
		scanner.Scan()
		k, _ := strconv.Atoi(scanner.Text())
		for i := 0; i < k; i++ {
			scanner.Scan()
			buf_ := strings.Split(scanner.Text(), " ")
			p, _ := strconv.Atoi(buf_[0])
			q, _ := strconv.Atoi(buf_[1])
			r, _ := strconv.Atoi(buf_[2])
			switch r {
			case 0: fmt.Println(c_dist[p-1][q-1])
			case 1: fmt.Println(t_dist[p-1][q-1])
			}
		}
	}
}

C++: #include <iostream>
#include <iomanip>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <algorithm>
#include <functional>
#include <sstream>
#include <complex>
#include <regex>
#include <cmath>
#include <bitset>
#include <array>
#include <deque>
#include <list>
#include <stack>
#include <iterator>
#include <random>

using namespace std;

extern void* enabler;
using LL=long long int;
using ULL=unsigned long long int;
using Complex=complex<double>;

template<class T>
using asc_pqueue=std::priority_queue<T,vector<T>, std::greater<T>>;
template<class T>
using desc_pqueue=std::priority_queue<T,vector<T>, std::less<T>>;
template<class T>
using asc_set=std::set<T,vector<T>, std::greater<T>>;
template<class T>
using desc_set=std::set<T,vector<T>, std::less<T>>;

const LL INF = (1ll << 62);


#include <algorithm>
#include <utility>

//=====debug======
#define debug(...) cerr << (__VA_ARGS__) << endl;

template<typename T>
class has_begin_and_end
{
    private:
    template<typename U>
    static auto check( U v ) -> decltype( v.begin(), v.end(), std::true_type() );
    static auto check( ... ) -> decltype( std::false_type() );

    public:
    typedef decltype( check( std::declval<T>() ) ) type;
    static bool const value = type::value;
};
template<typename T>
class has_top_and_pop
{
    private:
    template<typename U>
    static auto check( U v ) -> decltype( v.empty(), v.top(), v.pop(), std::true_type() );
    static auto check( ... ) -> decltype( std::false_type() );

    public:
    typedef decltype( check( std::declval<T>() ) ) type;
    static bool const value = type::value;
};
template<typename T>
class has_front_and_pop
{
    private:
    template<typename U>
    static auto check( U v ) -> decltype( v.empty(), v.front(), v.pop(), std::true_type() );
    static auto check( ... ) -> decltype( std::false_type() );

    public:
    typedef decltype( check( std::declval<T>() ) ) type;
    static bool const value = type::value;
};

template<class T, typename std::enable_if<has_begin_and_end<T>::value>::type*& = enabler>
void dump(const T& val){
    for(auto& v : val){
        debug(v);
    }
}
template<class T, typename std::enable_if<has_top_and_pop<T>::value>::type*& = enabler>
void dump(T val){
    while(!val.empty()){
        debug(val.top());
        val.pop();
    }
}
template<class T, typename std::enable_if<has_front_and_pop<T>::value>::type*& = enabler>
void dump(T val){
    while(!val.empty()){
        debug(val.front());
        val.pop();
    }
}

//=====pair-utility=====

template<class T, class U>
ostream& operator<<(ostream& os, const pair<T,U>& v)
{
    os << "(" <<  v.first <<  ", " << v.second << ")";
    return os;
}

template<class T, class U>
istream& operator>>(istream& is, pair<T,U>& v)
{
    is >> v.first;
    is >> v.second;
    return is;
}

#define def_pair_op(op) template<class T, class U> \
auto operator op(const pair<T,U>& a, const pair<T,U>& b) -> pair<decltype(a.first op b.first), decltype(a.second op b.second)> \
{ \
    return make_pair(a.first op b.first,a.second op b.second); \
} \
template<class T, class U, class V> \
auto operator op(const pair<T,U>& a, V b) -> pair<decltype(a.first op b), decltype(a.second op b)> \
{ \
    return make_pair(a.first op b, a.second op b); \
}

def_pair_op(+)
def_pair_op(-)
def_pair_op(*)
def_pair_op(/)
def_pair_op(%)
#undef def_pair_op


//=====clamp=====

template<class T>
T clamp(const T& val, const T& a, const T& b){
    return min(a, max(val, b));
}

template<class T,class U>
pair<T,U> clampPair(const pair<T,U>& val, const pair<T,U>& a, const pair<T,U>& b){
    return {clamp(val.first,a.first,b.first), clamp(val.second,a.second,b.second)};
}

//=====hash=====

template<std::size_t... idx>
struct index_sequence{
        typedef index_sequence<idx..., sizeof...(idx)> next;
            static constexpr size_t size() { return sizeof...(idx); }
};

template<std::size_t idx>
struct build_tuple{
        typedef typename build_tuple<idx-1>::type::next type;
};

template<>
struct build_tuple<0>{
        typedef index_sequence<> type;
};


template<std::size_t N>
using make_index_sequence = typename build_tuple<N>::type;
    

namespace std {
    template<class... T>
        class hash<std::tuple<T...>> {
            template<size_t... I>
                size_t impl(const std::tuple<T...>& t, ::index_sequence<I...>) const{
                    initializer_list<size_t> h{std::hash<typename std::tuple_element<I, std::tuple<T...>>::type>()(std::get<I>(t))...};
                    size_t a = accumulate(h.begin(), h.end(), 0, [](size_t a, size_t b){return a ^ b;});
                    return a;
                }
            public:
            size_t operator()(const std::tuple<T...> &t) const 
            {
                return impl(t, ::make_index_sequence<std::tuple_size<std::tuple<T...>>::value>());
            }
        };
}


//=====complex=====

template<class T>
bool operator<(const complex<T>& a, const complex<T>& b){
    if(a.real() == b.real())
        return a.imag() < b.imag();
    return a.real() < b.real();
}
template<class T>
bool operator>(const complex<T>& a, const complex<T>& b){
    if(a.real() == b.real())
        return a.imag() > b.imag();
    return a.real() > b.real();
}

class edge{
public:
    int from;
    int to;
    LL cost;

    edge(){}
    edge(int f,int t,LL c)
        : from(f), to(t), cost(c)
    {
    }
    edge reverse() const
    {
        return {to,from,cost};
    }
};

class graph{
public:
    int size; //????????°
    vector<vector<edge>> edges;
    graph(){
    }
    graph(int n)
        : edges(n), size(n)
    {
    }
    void init(int _size){
        edges.clear();
        edges.resize(_size);
        size = _size;
    }
    void push_edge(const edge& e){
        edges[e.from].push_back(e);
        edges[e.to].push_back(e.reverse());
    }
};

class dijkstra_result{
public:
    const vector<LL> cost; //???????????¢
    const LL result;

    dijkstra_result(const vector<LL>& c, LL res)
        : cost(c), result(res)
    {
    }
    dijkstra_result(const vector<LL>&& c, LL res)
        : cost(c), result(res)
    {
    }
};

dijkstra_result dijkstra(const graph& g, int from, int to, bool all = false){
    asc_pqueue<pair<LL,int>> que;
    vector<LL> v(g.size);
    vector<bool> f(g.size);
    fill(v.begin(), v.end(), INF);
    que.push({0, from});
    v[from] = 0;
    while(!que.empty() || !(!all && f[to])){
        auto p = que.top();
        que.pop();
        int n = p.second;
        if(v[n] < p.first)
            continue;
        f[n] = true;
        for(const auto& m : g.edges[n]){
            if(v[m.to] > v[n] + m.cost){
                v[m.to] = min(v[n] + m.cost, v[m.to]);
                que.push({v[m.to], m.to});
            }
        }
    }
    int r = v[to];
    return {v, r};
}
//#include "library/interval.h"
//#include "library/maybe.h"
//#include "library/utility.h"
//#include "library/rectangle.h"

//==========

int main(){
    int n,m;
    cin >> n >> m;
    graph g1(m+1),g2(m+1);
    for(int i=0;i<n;i++){
        int x,y,a,b;
        cin >> x >> y >> a >> b;
        g1.push_edge({x,y,a});
        g2.push_edge({x,y,b});
    }
    int q;
    cin >> q;
    for(int i=0;i<q;i++){
        int s,g,t;
        cin >> s >> g >> t;
        auto res = dijkstra(t == 0 ? g1 : g2, s, g);
        cout << res.result << endl;
    }
    return 0;
}