#include <bits/stdc++.h>
using namespace std;
inline int read() {
  int neg = 1, num = 0;
  char c = getchar();
  for (; !isdigit(c); c = getchar())
    if (c == '-') neg = -1;
  for (; isdigit(c); c = getchar()) num = (num << 1) + (num << 3) + c - '0';
  return neg * num;
}
struct edge1 {
  int nxt, to;
  long long val;
} Edge[300010 << 1];
struct edge2 {
  int u, v;
  long long val;
} E[300010 << 1];
struct node {
  int x;
  long long dis;
  bool operator<(const node &u) const { return u.dis < dis; }
};
int n, m, k, q, cnt, tot, head[300010], dep[300010], fa[300010], Fa[300010][25],
    pre[300010];
long long dis[300010], mx[300010][25];
bool inque[300010];
bool cmp(edge2 x, edge2 y) { return x.val < y.val; }
inline int Find(int x) { return fa[x] == x ? x : (fa[x] = Find(fa[x])); }
inline void Add_edge(int u, int v, int w) {
  Edge[++cnt].nxt = head[u];
  Edge[cnt].to = v;
  Edge[cnt].val = w;
  head[u] = cnt;
}
inline void Dijkstra() {
  priority_queue<node> q;
  for (int i = 1; i <= n; i++) dis[i] = (1ll << 60), inque[i] = 0;
  for (int i = 1; i <= k; i++) dis[i] = 0, pre[i] = i, q.push((node){i, 0});
  while (!q.empty()) {
    node u = q.top();
    q.pop();
    if (inque[u.x]) continue;
    inque[u.x] = 1;
    for (int i = head[u.x]; i; i = Edge[i].nxt) {
      int v = Edge[i].to;
      if (dis[v] > dis[u.x] + Edge[i].val) {
        dis[v] = dis[u.x] + Edge[i].val;
        pre[v] = pre[u.x];
        if (!inque[v]) q.push((node){v, dis[v]});
      }
    }
  }
}
inline void Kruskal() {
  cnt = 0;
  sort(E + 1, E + tot + 1, cmp);
  for (int i = 1; i <= tot && cnt / 2 != n - 1; i++) {
    int u = E[i].u, v = E[i].v;
    if (Find(u) == Find(v)) continue;
    fa[Find(u)] = fa[Find(v)];
    Add_edge(u, v, E[i].val);
    Add_edge(v, u, E[i].val);
  }
}
inline void dfs(int u) {
  dep[u] = dep[Fa[u][0]] + 1;
  for (int i = 0; i <= 21; i++)
    Fa[u][i + 1] = Fa[Fa[u][i]][i],
              mx[u][i + 1] = max(mx[Fa[u][i]][i], mx[u][i]);
  for (int i = head[u]; i; i = Edge[i].nxt) {
    int v = Edge[i].to;
    if (v == Fa[u][0]) continue;
    Fa[v][0] = u;
    mx[v][0] = Edge[i].val;
    dfs(v);
  }
}
inline long long LCA(int u, int v) {
  if (dep[u] < dep[v]) swap(u, v);
  long long ans = 0;
  for (int i = 22; i >= 0; i--)
    if (dep[Fa[u][i]] >= dep[v]) {
      ans = max(ans, mx[u][i]);
      u = Fa[u][i];
    }
  if (u == v) return ans;
  for (int i = 22; i >= 0; i--)
    if (Fa[u][i] != Fa[u][i]) {
      ans = max(ans, max(mx[u][i], mx[v][i]));
      u = Fa[u][i];
      v = Fa[v][i];
    }
  return max(ans, max(mx[u][0], mx[v][0]));
}
int main() {
  n = read();
  m = read();
  k = read();
  q = read();
  for (int i = 1; i <= m; i++) {
    int u = read(), v = read(), w = read();
    Add_edge(u, v, w);
    Add_edge(v, u, w);
    E[i].u = u;
    E[i].v = v;
    E[i].val = w;
  }
  Dijkstra();
  for (int i = 1; i <= m; i++) {
    if (pre[E[i].u] == pre[E[i].v]) continue;
    E[++tot].u = pre[E[i].u];
    E[tot].v = pre[E[i].v];
    E[tot].val = dis[E[i].u] + dis[E[i].v] + E[i].val;
  }
  for (int i = 1; i <= n; i++) fa[i] = i, head[i] = 0;
  Kruskal();
  dfs(1);
  if (n >= 100) printf("%d\n", tot);
  for (int i = 1; i <= q; i++) {
    int u = read(), v = read();
    printf("%lld\n", LCA(u, v));
  }
  return 0;
}
