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




class DSU{
public:
    vector<int> parent;
    DSU(int size){
        parent = vector<int>(size);
        iota(parent.begin(), parent.end(), 0);
    }

    int find(int x){
        if(x != parent[x]) parent[x] = find(parent[x]);
        return parent[x];
    }

    void merge(int x, int y){
        parent[find(y)] = x;
    }
};

class ListDSU{
public:
    vector<int> parent;
    vector<list<pair<int, int>>> lists;
    explicit ListDSU(int size){
        parent = vector<int>(size);
        iota(parent.begin(), parent.end(), 0);
        // for one element -> <ele, cost>, <ele2, cost2> ...
        lists = vector<list<pair<int, int>>>(size);
    }

    int find(int x){
        if(x != parent[x]) parent[x] = find(parent[x]);
        return parent[x];
    }
    // merges y into x
    void merge(int x, int y, int cost){
        list<pair<int, int>> &par = lists[find(x)];
        par.emplace_back(find(y), cost);
        par.splice(par.end(), lists[find(y)]);
        parent[find(y)] = x;
    }
};

class SparseTable {
public:
    vector<vector<int>> st;
    vector<int> log;

    SparseTable(vector<int> candidate) {
        int N = candidate.size();
        log = vector<int>(N + 1);
        log[1] = 0;
        for (int i = 2; i <= N; ++i) {
            log[i] = log[i >> 1] + 1;
        }

        int K = log[N] + 1;

        st = vector<vector<int>>(N, vector<int>(K));
        for (int i = 0; i < N; ++i) {
            st[i][0] = candidate[i];
        }
        for (int j = 1; j <= K; j++) {
            for (int i = 0; i + (1 << j) <= N; i++) {
                st[i][j] = max(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);
            }
        }
    }

    int query(int L, int R) {
        int j = log[R - L + 1];
        return max(st[L][j], st[R - (1 << j) + 1][j]);
    }
};

vector<tuple<int, int, int>> kruskall(int n, vector<vector<pair<int, int>>> &graph){

    vector<tuple<int, int, int>> edges;
    for(int i = 0; i < graph.size(); ++i){
        for(auto [u, w]: graph[i]){
            edges.emplace_back(w, u, i);
        }
    }

    vector<tuple<int, int, int>> keep;
    DSU dsu(n);
    sort(edges.begin(), edges.end());

    for(auto [w, u, v]: edges){
        if(dsu.find(u) != dsu.find(v)){
            dsu.merge(u, v);
            keep.emplace_back(u, v, w);
        }
    }
    return keep;
}


int main(){
    int n, m, k, q;
    cin >> n >> m >> k >> q;

    vector<vector<pair<int, int>>> graph(n);

    for(int i = 0; i < m; ++i){
        int u, v, w;
        cin >> u >> v >> w;
        --u, --v;
        graph[u].emplace_back(v, w);
        graph[v].emplace_back(u, w);
    }
//    cout << "graph built" << endl;
    priority_queue<pair<int, int>, vector<pair<int, int>>, greater<>> dijkstra;
    for(int i = 0; i < k; ++i) dijkstra.emplace(0, i);

    vector<int> closest(n, -1);
    while(!dijkstra.empty()){
        auto [cost, node] = dijkstra.top();
//        cout << node << " " << cost << endl;
        dijkstra.pop();
        if(closest[node] == -1){
            closest[node] = cost;
            for(auto [nei, w]: graph[node]){
                if(closest[nei] == -1){
                    dijkstra.emplace(w + cost, nei);
                }
            }
        }
    }

//    for(auto i: closest) cout << i << " ";
//    cout << endl;
//
//    cout << "dijkstra finish" << endl;

    for(int i = 0; i < graph.size(); ++i){
        for(auto &edge: graph[i]){
            edge.second += closest[i] + closest[edge.first];
        }
    }

    ListDSU ldsu(n);

    for(auto& [u, v, w]: kruskall(n, graph)){
//        cout << u << " " << v << " " << w << endl;
        ldsu.merge(u, v, w);
    }

//    cout << "----------------" << endl;

    list<pair<int, int>> line_tree = ldsu.lists[ldsu.find(0)];

    vector<int> sparse = {0};
    vector<int> map(n);
    for(auto [node, cst]: line_tree){
        sparse.push_back(cst);
        map[node] = sparse.size();
        sparse.push_back(0);
    }

    SparseTable tb(sparse);

    for(int i = 0; i < q; ++i){
        int u, v;
        cin >> u >> v;
        --u, --v;
        u = map[u];
        v = map[v];
        if(u > v) swap(u, v);
        cout << tb.query(u, v) << endl;
    }

}