#include <bits/stdc++.h>
#define int long long
#define double long double
#define endl "\n"
#define fastio ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define pb push_back
#define mp make_pair
#define ms(v,x) memset(v,x,sizeof(v))
#define pii pair<int,int>
#define ff first
#define ss second
#define frr(i,n) for(int i=0;i<n;i++)
#define rep(i,j,k) for(int i=j;i<k;i++)
#define td(v) v.begin(),v.end()
#define inf 1000000000 // 1e9
#define M   1000000007 // 1e9 + 7
using namespace std;
inline int mod(int n, int m){ int ret = n%m; if(ret < 0) ret += m; return ret; }
int gcd(int a, int b){return (b == 0 ? a : gcd(b, a%b));}
int lcm(int a,int b){return (a*b)/gcd(a,b);}
int exp(int a,int b,int m){
    if(b==0) return 1LL;
    if(b==1) return mod(a,m);
    int k = mod(exp(a,b/2,m),m);
    if(b&1){
        return mod(a*mod(k*k,m),m);
    }
    else return mod(k*k,m);
}
vector<pii> adj[100100];
vector<pii> mst[100100];
int n,m,k,q;
vector<int> p(100100);
vector<int> sz(100100);
struct node{
    int cost, u, origin;
    bool operator<(const node& y) const{
        return cost < y.cost;
    }
};
struct edge{
    int u,v,c;
    bool operator<(const edge& w){
        return c < w.c;
    }
};
int find_set(int v) {
    if (v == p[v])
        return v;
    return p[v] = find_set(p[v]);
}
void make_set(int v) {
    p[v] = v;
    sz[v] = 1;
}
void union_sets(int a, int b) {
    a = find_set(a);
    b = find_set(b);
    if (a != b) {
        if (sz[a] < sz[b])
            swap(a, b);
        p[b] = a;
        sz[a] += sz[b];
    }
}

namespace LCA{
    int anc[20][100010];
    int mw[20][100010];
    int pai[100010],tin[100010],tout[100010];
    int tempo = 0;
    void dfs(int u,int p){
        pai[u] = p;
        tin[u] = tempo++;
        for(pii v : mst[u])
            if(v.ff != p){
                mw[0][v.ff] = v.ss;
                dfs(v.ff,u);
            }
        tout[u] = tempo++;
    }
    void precompute(){
        dfs(1,-1);
        for(int i=1;i<=n;i++){
            anc[0][i] = pai[i];
        }
        for(int i=1;i<20;i++){
            for(int j=1;j<=n;j++){
                mw[i][j] = (anc[i-1][j] == -1 ? 0 : max(mw[i-1][anc[i-1][j]],mw[i-1][j]));
                anc[i][j] = (anc[i-1][j] == -1 ? -1 : anc[i-1][anc[i-1][j]]);       
            }
        }
    }
    bool is_anc(int x,int y){ // is x ancestor of y
        return (tin[x] <= tin[y] && tout[x] >= tout[y]);    
    }
    int lca(int x,int y){
        if(is_anc(x,y)) return x;
        if(is_anc(y,x)) return y;

        int cur = x;
        for(int i=19;i>=0;i--){
            int k = anc[i][cur];
            //cout << k << " ";
            if(k==-1) continue;
            if(!is_anc(k,y)){
                cur = k;
            }
        }
        return pai[cur];
    }
    int do_rmq(int x,int y){ // maior peso entre x,y obs: x = lca(x,y)
        int maximum_weight = -1;
        int cur = y;
        for(int i=19;i>=0;i--){
            int k = anc[i][cur];
            if(k==-1){
                continue;
            }
            if(!is_anc(k,x)){
                maximum_weight= max(maximum_weight,mw[i][cur]);
                cur = k;
            }
        }
        if(cur!=x) maximum_weight = max(maximum_weight,mw[0][cur]);
        return maximum_weight;
    }
    int rmq(int x,int y){
        if(x==y){
            return 0;
        }
        int z = lca(x,y);
        return max(do_rmq(z,x), do_rmq(z,y)); 
    }
}
main(){
    fastio;
    cin >> n >> m >> k >> q;
    rep(i,0,n+1) make_set(i);
    for(int i=0;i<m;i++){
        int a,b,c;
        cin >> a >> b >> c;
        adj[a].pb({b,c});
        adj[b].pb({a,c});
    }
    vector<int> dist(100100,(1LL<<62));
    priority_queue<node> pq;
    rep(i,1,k+1){
        pq.push({0,i,i});
        dist[i] = 0;
    }
    vector<edge> edges;
    while(!pq.empty()){
        node w = pq.top();
        pq.pop();
        if(w.cost != dist[w.u]) continue;
        int c = w.cost;
        for(pii &v : adj[w.u]){
            if(v.ff <= k){
                edges.pb({w.origin,v.ff,c + v.ss});
            }
            else if(c + v.ss < dist[v.ff]){
                dist[v.ff] = c + v.ss;
                pq.push({dist[v.ff], v.ff, w.origin});
            }
        }
    }
    sort(td(edges));
    for(auto &x : edges){
        if(find_set(x.u) != find_set(x.v)){
            mst[x.u].pb({x.v,x.c});
            mst[x.v].pb({x.u,x.c});
            //cout << x.u << " " << x.v << " " << x.c << endl;
            union_sets(x.u,x.v);
        }
    }
    LCA::precompute();

    while(q--){
        int x,y;
        cin >> x >> y;
        cout << LCA::rmq(x,y) << endl;
    }
    
}   