#include<bits/extc++.h>
#ifdef _debug 
#define dout(i) cout << #i << ' ' << i << ' '
#else 
#define getchar_unlocked  _getchar_nolock
#include<bits/stdc++.h>
#define dout(i) 0&&0
#endif
#pragma GCC optimize("unroll-loops,no-stack-protector,O3")
#define priority_queue __gnu_pbds::priority_queue
#define unordered_map __gnu_pbds::gp_hash_table
#define rep(_n) for(int __i = _n;__i--;)
#define rep0(_i, _n) for(int _i = 0; (_i)<(_n) ;++_i)
#define rep1(_i, _n) for(int _i = 1; (_i)<=(_n) ;++_i)
#define yn(i) ((i)?"Yes" : "No")
#define eout(i) {cout << (i) << '\n';exit(0);}
#define rout(i) {return cout << (i) << '\n', 0;}
#define multi int _T;for(cin >> _T;_T--;)
using namespace std;
using ll = long long;using ull = unsigned long long;using ul = unsigned;using db = double;
using __gnu_pbds::null_type;
inline void read(char &a){static char p; while(isspace(p = getchar_unlocked())); a = p; }
inline void read(string &a){static char p; while(isspace(p = getchar_unlocked())); a = p; while(!isspace(p = getchar_unlocked()))a.push_back(p);}
template<typename T> inline void read(T& a){static char p; static bool b; while (!isdigit(p = getchar_unlocked()))b = p == '-'; a = p ^ '0'; while (isdigit(p = getchar_unlocked())) a *= 10, a += p ^ '0'; if(b)a *= -1; }
template<typename T> inline void read(T begin, const T &end){while(begin != end)read(*begin), ++begin;}
template<typename T> inline void write(T begin, const T &end){while(begin != end)cout << *begin << " \n"[next(begin) == end], ++begin;}
template<typename T> using rbtree = __gnu_pbds::tree<T,__gnu_pbds::null_type,less<T>,__gnu_pbds::rb_tree_tag,__gnu_pbds::tree_order_statistics_node_update>;
template<typename T> inline ostream& operator << (ostream &ou, const vector<T> &a){for(auto it = a.begin();it != a.end();++it)ou << (it != a.begin() ? " " : "") << *it;return ou;}
template<typename T1, typename T2>inline istream& operator >> (istream &in, pair<T1, T2> &a){return in >> a.first >> a.second;}
template<typename T1, typename T2>inline ostream& operator << (ostream &ou, const pair<T1, T2> &b){return ou << b.first << ' ' << b.second;}
template<typename T> inline long long pow(long long v, long long t, const T &p){long long res = 1;for(;t;t >>= 1, v = v * v % p)if(t & 1)res = res * v % p;return res;}
const int maxn = 300010;
#define int ll
int n, m, k, q;
vector<pair<int,int>> edge[maxn];
vector<pair<ll, pair<int,int>> > mst;
ll dis[maxn];
const ll inf = 1ll<<59;
int mo[maxn], ml;
int vis[maxn];
ll curmin[maxn];
void dij(int s){
    priority_queue<pair<int,int>, greater<pair<int,int>> > togo;
    for(const auto &[id, w] : edge[s]){
        dis[id] = w;
        togo.push({w, id});
    }
    vis[s] = s;
    while(togo.size()){
        int id;ll w;
        tie(w, id) = togo.top();
        togo.pop();
        if(w >= curmin[s])break;
        if(vis[id] != s){
            mo[ml++] = id;
            vis[id] = s;
            dis[id] = w;
            if(id <= k){
                mst.push_back({w, {s, id}}), curmin[id] = min(curmin[id], w);
                break;
            }
            else for(const auto &[eid, ew] : edge[id])if(vis[eid] != s and dis[eid] > w + ew){
                dis[eid] = w + ew;
                togo.push({w+ew, eid});
            }
        }
    }
    rep0(i, ml)dis[mo[i]] = inf;
    ml = 0;
}
int g[maxn];
int find(int i){
    return i == g[i] ? i : g[i] = find(g[i]);
}
const int maxk = 17;
ll dp[maxk][maxn];
int anc[maxk][maxn];
int in[maxn], out[maxn], dep[maxn];
bool isanc(int a, int b){
    return in[a] <= in[b] and out[a] >= out[b];
}
void dfs(int now, int last = 1, ll lw = 0){
    static int t;
    static int d;
    dep[now] = ++d;
    in[now] = ++t;
    anc[0][now] = last;
    dp[0][now] = lw;
    rep1(i, maxk-1){
        anc[i][now] = anc[i-1][ anc[i-1][now] ];
        dp[i][now] = max(dp[i-1][now], dp[i-1][ anc[i-1][now] ]);
    }
    for(const auto &[id, w] : edge[now])if(id != last){
        dfs(id,  now, w);
    }
    out[now] = t;
    --d;
}
ll query(int a, int b){
    if(dep[a] > dep[b])swap(a, b);
    ll res = 0;
    for(int i = maxk-1;i >= 0;--i)if(!isanc(anc[i][b], a)){
        res = max(res, dp[i][b]);
        b = anc[i][b];
    }
    res = max(res, dp[0][b]);
    b = anc[0][b];
    if(b == a)return res;
    swap(a, b);
    for(int i = maxk-1;i >= 0;--i)if(!isanc(anc[i][b], a)){
        res = max(res, dp[i][b]);
        b = anc[i][b];
    }
    res = max(res, dp[0][b]);
    return res;
}
void build(){
    sort(mst.begin(), mst.end());
    for(auto &i : mst){
        if(find(i.second.second) != find(i.second.first)){
            edge[i.second.first].emplace_back(i.second.second, i.first);
            edge[i.second.second].emplace_back(i.second.first, i.first);
            g[find(i.second.second)] = find(i.second.first);
        }
    }
    dfs(1);
}
signed main(){
    ios_base::sync_with_stdio(0), cin.tie(0);
    read(n), read(m), read(k), read(q);
    rep(m){
        int a, b, w;
        read(a), read(b), read(w);
        edge[a].emplace_back(b, w), edge[b].emplace_back(a, w);
    }   
    rep1(i, n)dis[i] = inf;
    rep1(i, k)curmin[i] = inf;
    rep1(i, k)dij(i), g[i] = i;
    // for(auto u : mst)cout << u << '\n';
    rep1(i, n)edge[i].clear();
    build();
    rep(q){
        int a, b;
        read(a), read(b);
        printf("%lld\n", query(a, b));
    }
}