#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;

//-----桁指定出力-------
// %8d: cout << setw(8);
// %08d: cout << setw(8) << setfill('0');

//=====別名・定数定義=====

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};
}

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

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;
}