#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 69;
int n, k, m, q;
int par[N], P[N][21], sz[N], in[N], out[N], fix[N], D[N], C[N];
long long MX[N][21];
int timer;
vector<pair<int, long long> > gr[N], gr1[N];
vector<pair<long long, pair<int, int> > > v;
pair<pair<int, int>, long long> edge[N];
priority_queue<pair<int, int> > Q;
int find_set(int x) {
  if (par[x] == x) return x;
  return par[x] = find_set(par[x]);
}
void union_set(int a, int b) {
  if (sz[a] < sz[b]) swap(a, b);
  par[b] = a;
  sz[a] += sz[b];
}
void dfs(int x, int p) {
  timer++;
  in[x] = timer;
  fix[x] = 1;
  P[x][0] = p;
  for (int i = 1; i <= 20; i++) {
    P[x][i] = P[P[x][i - 1]][i - 1];
    MX[x][i] = max(MX[x][i - 1], MX[P[x][i - 1]][i - 1]);
  }
  for (int i = 0; i < gr1[x].size(); i++) {
    int to = gr1[x][i].first;
    if (fix[to]) continue;
    MX[to][0] = gr1[x][i].second;
    dfs(to, x);
  }
  out[x] = timer;
}
bool check(int x, int y) { return in[x] <= in[y] && out[x] >= out[y]; }
int lca(int x, int y) {
  if (check(x, y)) return x;
  if (check(y, x)) return y;
  for (int i = 20; i >= 0; i--)
    if (P[x][i] != 0 && !check(P[x][i], y)) x = P[x][i];
  return P[x][0];
}
long long get(int x, int y) {
  long long ans = 0;
  if (x == y) {
    return 0;
  }
  for (int i = 20; i >= 0; i--)
    if (P[x][i] != 0 && !check(P[x][i], y))
      ans = max(ans, MX[x][i]), x = P[x][i];
  ans = max(ans, MX[x][0]);
  return ans;
}
int main() {
  ios::sync_with_stdio(0);
  cin >> n >> m >> k >> q;
  for (int i = 0; i < m; i++) {
    int x, y, w;
    cin >> x >> y >> w;
    gr[x].push_back({y, w});
    gr[y].push_back({x, w});
    edge[i] = {{x, y}, w};
  }
  for (int i = 1; i <= n; i++) D[i] = 1e18;
  for (int i = 1; i <= k; i++) {
    Q.push({0, i});
    C[i] = i;
    D[i] = 0;
  }
  while (Q.size()) {
    pair<long long, int> p = Q.top();
    Q.pop();
    int x = p.second, d = p.first;
    for (int i = 0; i < gr[x].size(); i++) {
      int to = gr[x][i].first;
      long long w = gr[x][i].second;
      if (D[to] > d + w) {
        D[to] = d + w;
        C[to] = C[x];
        Q.push({D[to], to});
      }
    }
  }
  for (int i = 0; i < m; i++) {
    int x = edge[i].first.first;
    int y = edge[i].first.second;
    int w = edge[i].second;
    if (C[x] != C[y]) {
      v.push_back({D[x] + D[y] + w, {C[x], C[y]}});
    }
  }
  sort(v.begin(), v.end());
  for (int i = 1; i <= k; i++) {
    sz[i] = 1;
    par[i] = i;
  }
  for (int i = 0; i < v.size(); i++) {
    int x = v[i].second.first;
    int y = v[i].second.second;
    int w = v[i].first;
    int a = find_set(x);
    int b = find_set(y);
    if (a == b) continue;
    gr1[x].push_back({y, w});
    gr1[y].push_back({x, w});
    union_set(a, b);
  }
  dfs(1, 0);
  while (q--) {
    int x, y;
    cin >> x >> y;
    int u = lca(x, y);
    int a = get(x, u);
    int b = get(y, u);
    cout << max(a, b) << endl;
  }
}
