#include <bits/stdc++.h>
bool debug = false;
using namespace std;
constexpr int kN = int(1E5 + 10), LOGN = 20;
constexpr long long int kInf = long long int(1E16 + 10);
struct Edge {
  int to;
  long long int cost;
};
struct kEdge {
  int from, to;
  long long int cost;
};
bool cmp(kEdge a, kEdge b) { return a.cost < b.cost; }
vector<Edge> graph[kN], ngraph[kN];
vector<kEdge> kedge;
int from[kN], par[LOGN][kN], p[kN], dep[kN];
long long int dis[kN], ndis[LOGN][kN];
int Find(int n) { return p[n] == n ? n : p[n] = Find(p[n]); }
void dfs(int pos, int from) {
  for (Edge i : ngraph[pos])
    if (i.to != from) {
      par[0][i.to] = pos;
      ndis[0][i.to] = i.cost;
      dep[i.to] = dep[pos] + 1;
      dfs(i.to, pos);
    }
  return;
}
long long int dist(int l, int r) {
  long long int ans = 0;
  if (dep[l] < dep[r]) swap(l, r);
  for (int i = LOGN - 1; i >= 0; i--)
    if (dep[par[i][l]] > dep[r]) {
      ans = max(ans, ndis[i][l]);
      l = par[i][l];
    }
  if (dep[l] > dep[r]) {
    ans = max(ans, ndis[0][l]);
    l = par[0][l];
  }
  for (int i = LOGN - 1; i >= 0; i--)
    if (par[i][l] != par[i][r]) {
      ans = max(ans, max(ndis[i][l], ndis[i][r]));
      l = par[i][l];
      r = par[i][r];
    }
  if (l != r) ans = max(ans, max(ndis[0][l], ndis[0][r]));
  return ans;
}
int main() {
  int k, n, m, q, nxt, l, r, c;
  long long int val;
  priority_queue<pair<long long int, int>, vector<pair<long long int, int>>,
                 greater<pair<long long int, int>>>
      pq;
  scanf("%d%d%d%d", &n, &m, &k, &q);
  while (m--) {
    scanf("%d%d%d", &l, &r, &c);
    graph[l].push_back({r, c});
    graph[r].push_back({l, c});
  }
  for (int i = 1; i <= k; i++) from[i] = i;
  for (int i = 1; i <= k; i++) dis[i] = 0;
  for (int i = k + 1; i <= n; i++) from[i] = 0;
  for (int i = k + 1; i <= n; i++) dis[i] = kInf;
  for (int i = 1; i <= k; i++) pq.push({dis[i], i});
  while (!pq.empty()) {
    val = pq.top().first;
    nxt = pq.top().second;
    pq.pop();
    if (val > dis[nxt]) continue;
    for (Edge i : graph[nxt])
      if (val + i.cost < dis[i.to]) {
        dis[i.to] = val + i.cost;
        from[i.to] = from[nxt];
        pq.push({dis[i.to], i.to});
      }
  }
  if (debug) {
    for (int i = 1; i <= n; i++)
      printf("dis[%d] = %lld, from[%d] = %d\n", i, dis[i], i, from[i]);
  }
  for (int i = 1; i <= n; i++)
    for (Edge j : graph[i])
      if (from[i] != from[j.to])
        kedge.push_back({from[i], from[j.to], dis[i] + dis[j.to] + j.cost});
  sort(kedge.begin(), kedge.end(), cmp);
  for (int i = 1; i <= k; i++) p[i] = i;
  for (kEdge i : kedge) {
    l = Find(i.to);
    r = Find(i.from);
    if (l != r) {
      p[l] = r;
      ngraph[i.to].push_back({i.from, i.cost});
      ngraph[i.from].push_back({i.to, i.cost});
    }
  }
  if (debug) {
    for (int i = 1; i <= k; i++) {
      printf("%d::\n", i);
      for (Edge j : ngraph[i]) printf("to %d, cost %lld\n", j.to, j.cost);
    }
  }
  dep[1] = 0;
  ndis[0][1] = 0;
  par[0][1] = 0;
  dfs(1, 0);
  for (int i = 1; i < LOGN; i++)
    for (int j = 1; j <= k; j++) {
      par[i][j] = par[i - 1][par[i - 1][j]];
      ndis[i][j] = ndis[i - 1][j] + ndis[i - 1][par[i - 1][j]];
    }
  while (q--) {
    scanf("%d%d", &l, &r);
    printf("%lld\n", dist(l, r));
  }
}
