#include <bits/stdc++.h>
using namespace std;
const long long INF = 1e18;
const int MAXN = 1e5 + 5;
const int LOG = 22;
int n, m, k, q, len, tot;
int head[MAXN], vis[MAXN], f[MAXN][LOG], belong[MAXN], dep[MAXN];
long long val[MAXN][LOG], dis[MAXN];
struct Edge {
  int to, next;
  long long w;
} e[MAXN << 1];
struct Road {
  int u, v;
  long long w;
  Road() {}
  Road(int _u, int _v, long long _w) : u(_u), v(_v), w(_w) {}
  friend bool operator<(const Road &x, const Road &y) { return x.w < y.w; }
} edge[MAXN << 1];
struct Node {
  int u, s;
  long long dis;
  Node(int _u, int _s, long long _dis) : u(_u), s(_s), dis(_dis) {}
  friend bool operator>(const Node &x, const Node &y) { return x.dis > y.dis; }
};
void add(int u, int v, long long w) {
  e[++len].to = v;
  e[len].next = head[u];
  e[len].w = w;
  head[u] = len;
}
void dijkstra() {
  priority_queue<Node, vector<Node>, greater<Node> > que;
  for (int i = 1; i <= n; i++) {
    dis[i] = INF;
    vis[i] = 0;
  }
  for (int i = 1; i <= k; i++) {
    dis[i] = 0;
    que.push(Node(i, i, 0));
  }
  while (!que.empty()) {
    Node cur = que.top();
    que.pop();
    int u = cur.u;
    if (vis[u]) continue;
    belong[u] = cur.s;
    vis[u] = 1;
    for (int i = head[u]; i != -1; i = e[i].next) {
      int v = e[i].to;
      if (dis[v] > dis[u] + e[i].w) {
        dis[v] = dis[u] + e[i].w;
        que.push(Node(v, cur.s, dis[v]));
      }
    }
  }
}
namespace Dsu {
int f[MAXN];
void Init() {
  for (int i = 0; i < MAXN; i++) f[i] = i;
}
int find(int x) {
  if (x == f[x])
    return x;
  else
    return f[x] = find(f[x]);
}
void unionn(int x, int y) {
  int fx = find(x);
  int fy = find(y);
  if (fx != fy) f[fx] = fy;
}
}  // namespace Dsu
void MST() {
  len = 0;
  memset(head, -1, sizeof(head));
  sort(edge + 1, edge + tot + 1);
  Dsu::Init();
  for (int i = 1; i <= tot; i++) {
    int u = edge[i].u, v = edge[i].v, w = edge[i].w;
    int fx = Dsu::find(u), fy = Dsu::find(v);
    if (fx != fy) {
      add(fx, fy, w);
      add(fy, fx, w);
      Dsu::unionn(fx, fy);
    }
  }
}
void dfs(int u, int fa) {
  for (int i = 1; i < LOG; i++) {
    f[u][i] = f[f[u][i - 1]][i - 1];
    val[u][i] = max(val[u][i - 1], val[f[u][i - 1]][i - 1]);
  }
  for (int i = head[u]; i != -1; i = e[i].next) {
    int v = e[i].to;
    if (v == fa) continue;
    val[v][0] = e[i].w;
    f[v][0] = u;
    dep[v] = dep[u] + 1;
    dfs(v, u);
  }
}
long long GetAns(int u, int v) {
  if (dep[u] < dep[v]) swap(u, v);
  long long res = 0;
  for (int i = LOG - 1; i >= 0; i--) {
    if (dep[f[u][i]] >= dep[v]) {
      res = max(res, val[u][i]);
      u = f[u][i];
    }
  }
  if (u == v) return res;
  for (int i = LOG - 1; i >= 0; i--) {
    if (f[u][i] != f[v][i]) {
      res = max(res, val[u][i]);
      res = max(res, val[v][i]);
      u = f[u][i];
      v = f[u][i];
    }
  }
  res = max(res, val[u][0]);
  res = max(res, val[v][0]);
  return res;
}
int main() {
  memset(head, -1, sizeof(head));
  scanf("%d%d%d%d", &n, &m, &k, &q);
  for (int i = 1; i <= m; i++) {
    int x, y;
    long long z;
    scanf("%d%d%lld", &x, &y, &z);
    add(x, y, z);
    add(y, x, z);
  }
  dijkstra();
  for (int u = 1; u <= n; u++) {
    for (int i = head[u]; i != -1; i = e[i].next) {
      int v = e[i].to;
      if (belong[u] != belong[v])
        edge[++tot] = Road(belong[u], belong[v], dis[u] + dis[v] + e[i].w);
    }
  }
  MST();
  dfs(1, 0);
  while (q--) {
    int x, y;
    scanf("%d%d", &x, &y);
    printf("%lld\n", GetAns(x, y));
  }
  return 0;
}
