#pragma GCC optimize ("O3")
#pragma GCC target ("sse4")

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/rope>

#define ll long long
#define ordered_set tree<int, null_type,less<int>, rb_tree_tag,tree_order_statistics_node_update>

using namespace std;

const int nax = 1e5 + 1;
vector<pair<int, ll>> g[nax], tree[nax];
int par[nax][21], depth[nax];
ll mx[nax][21];
int n, m, k, q;
int fr[nax];
ll cost[nax];

void addedge(int u, int v, int w) {
    g[u].push_back({v, w});
    g[v].push_back({u, w});
}

void dij() {
    priority_queue<pair<int, int>> q;
    for (int i = 1; i <= n; i++)cost[i] = 1e18;
    cost[1] = 0;
    fr[1] = 1;
    q.push({0, 1});
    while (q.size()) {
        int u = q.top().second;
        ll cst = -q.top().first;
        if (u <= k && fr[u] != u) {
            assert(cst);
            tree[fr[u]].push_back({u, cst});
            tree[u].push_back({fr[u], cst});
            // cout << fr[u] << ' ' << u << ' ' << cst << endl;
            fr[u] = u;
            cost[u] = 0;
            cst = cost[u];
        }
        q.pop();
        if (cost[u] < cst)continue;
        for (pair<int, int> curnode : g[u]) {
            int v = curnode.first;
            ll w = curnode.second;
            ll ncst = cst + w;
            if (ncst >= cost[v])continue;
            cost[v] = ncst;
            fr[v] = fr[u];
            q.push({-cost[v], v});
        }
    }
}

void dfs(int u, int p) {
    for (pair<int, ll> curnode : tree[u]) {
        int v = curnode.first;
        ll w = curnode.second;
        if (v == p)continue;
        depth[v] = depth[u] + 1;
        par[v][0] = u;
        mx[v][0] = w;
        dfs(v, u);
    }
}

pair<ll, int> kth(int u, int dis) {
    ll big = 0;
    for (int k = 20; k >= 0; k--) {
        if ((dis >> k) & 1) {
            big = max(big, mx[u][k]);
            assert(mx[u][k]);
            u = par[u][k];
        }
    }
    return {big, u};
}

ll lca(int u, int v) {
    if (depth[u] < depth[v])swap(u, v);
    int dis = depth[u] - depth[v];
    pair<ll, int> nxt = kth(u, dis);
    ll big = nxt.first;
    u = nxt.second;
    // cout << u << ' ' << v << endl;
    if (u == v) {
        return big;
    }
    for (int k = 20; k >= 0; k--) {
        if (par[u][k] != par[v][k]) {
            big = max(big, max(mx[v][k], mx[u][k]));
            assert(mx[u][k]);
            assert(mx[v][k]);
            u = par[u][k];
            v = par[v][k];
        }
    }
    // cout << u << ' ' << v << endl;
    big = max(big, max(mx[u][0], mx[v][0]));
    return big;
}

int main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    cin >> n >> m >> k >> q;
    for (int i = 0; i < m; i++) {
        int u, v, w;
        cin >> u >> v >> w;
        addedge(u, v, w);
    }
    dij();
    dfs(1, 0);
    for (int k = 1; k < 20; k++) {
        for (int i = 1; i <= n; i++) {
            par[i][k] = par[par[i][k - 1]][k - 1];
            mx[i][k] = max(mx[i][k - 1], mx[par[i][k - 1]][k - 1]);
        }
    }
    while (q--) {
        int a, b;
        cin >> a >> b;
        cout << lca(a, b) << '\n';
    }
    return 0;
}