#include <bits/stdc++.h>

using namespace std;

struct Edge {
    int u;
    int v;
    long long c;
    Edge() {}
    Edge(int u, int v, long long c): u(u), v(v), c(c) {}
};

template <typename T>
struct SimplePQ {
    // Each element in the priority queue is a key from {0,...,n-1} and a priority (type T).
    // Each key can only be popped at most once - after that it is ignored.
    // The value of a key can only be decreased. If it is otherwise changed this is ignored.
    int n;
    vector<pair<T, int>> heap;
    int heap_size;
    int num_popped;
    vector<int> pos; // pos[key] is the position of key in the heap. With -1 if it is not inserted yet.
    vector<bool> popped;
    T inf;
    SimplePQ(int n, T inf): n(n), heap(n), heap_size(0), num_popped(0), pos(n, -1), popped(n, false), inf(inf) {}
    int size() {
        return heap_size - num_popped;
    }
    bool empty() {
        return size() == 0;
    }
    pair<T, int> top() {
        // assert(heap_size > 0);
        return heap[0];
    }
    void swap_pos(int i, int j) {
        swap(heap[i], heap[j]);
        pos[heap[i].second] = i;
        pos[heap[j].second] = j;
    }
    void erase(int k) {
        if (2*k+1 >= heap_size) {
            // nothing to do
        } else if (2*k+2 >= heap_size || heap[2*k+1] < heap[2*k+2]) {
            swap_pos(k, 2*k+1);
            erase(2*k+1);
        } else {
            swap_pos(k, 2*k+2);
            erase(2*k+2);
        }
    }
    void pop() {
        // assert(heap_size > 0);
        int key = heap[0].second;
        erase(0);
        heap[pos[key]] = make_pair(inf, key);
        popped[key] = true;
        ++num_popped;
    }
    void set_priority(int key, T value) {
        // assert(0 <= key && key < n);
        if (popped[key]) {
            // Nothing to do since it is already popped
        } else if (pos[key] == -1) {
            heap[heap_size] = make_pair(value, key);
            pos[key] = heap_size;
            ++heap_size;
            heap_up(pos[key]);
        } else if (value < heap[pos[key]].first) {
            heap[pos[key]].first = value;
            heap_up(pos[key]);
        }
    }
    void heap_up(int i) {
        int parent = (i-1)/2;
        if (i > 0 && heap[parent] > heap[i]) {
            swap_pos(i, parent);
            heap_up(parent);
        }
    }
};

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    auto t0 = clock();
    int n, m;
    long long l;
    cin >> n >> m >> l;
    vector<vector<Edge>> adj_list(n);
    for (int i = 0; i < m; ++i) {
        int a, b;
        long long c;
        cin >> a >> b >> c;
        --a;
        --b;
        if (c <= l) {
            adj_list[a].push_back(Edge(a, b, c));
            adj_list[b].push_back(Edge(b, a, c));
        }
    }
    int q;
    cin >> q;
    vector<pair<int, int>> queries(q);
    for (int i = 0; i < q; ++i) {
        cin >> queries[i].first >> queries[i].second;
        --queries[i].first;
        --queries[i].second;
    }
    auto dijkstra = [&](int start_id) {
        SimplePQ<pair<int, long long>> pq(n, make_pair(n+10, 0));
        pq.set_priority(start_id, make_pair(0, 0LL));
        vector<int> dist(n, -1);
        while (!pq.empty()) {
            auto p = pq.top();
            int node_id = p.second;
            pq.pop();
            int num_tank = p.first.first;
            long long content = p.first.second;
            dist[node_id] = num_tank;
            for (auto& edge : adj_list[node_id]) {
                if (edge.c + content > l) {
                    pq.set_priority(edge.v, make_pair(num_tank + 1, edge.c));
                } else {
                    pq.set_priority(edge.v, make_pair(num_tank, edge.c + content));
                }
            }
        }
        return dist;
    };
    vector<vector<int>> dists(n);
    for (int i = 0; i < n; ++i) {
        dists[i] = dijkstra(i);
    }
    for (auto q : queries) {
        cout << dists[q.first][q.second] << "\n";
    }
    cerr << "time used = " << (clock() - t0) << endl;
    return 0;
}

Measured memory_bytes: 3968