#include <bits/stdc++.h>
using namespace std;
const int N = 10000;
const long double pi = acos(-1.0);
int n, m, k, ask, pa[100100], tot = 0;
struct edgenode {
  int u, v;
  long long w;
} edge[300300];
bool operator<(edgenode p, edgenode q) { return p.w < q.w; }
struct hnode {
  int u;
  long long dis;
};
bool operator<(hnode p, hnode q) { return p.dis > q.dis; }
priority_queue<hnode> q;
int find(int x) {
  if (pa[x] == x) return pa[x];
  pa[x] = find(pa[x]);
  return pa[x];
}
int read() {
  int x = 0, f = 1;
  char ch = getchar();
  while ((ch < '0') || (ch > '9')) {
    if (ch == '-') f = -1;
    ch = getchar();
  }
  while ((ch >= '0') && (ch <= '9')) {
    x = x * 10 + (ch - '0');
    ch = getchar();
  }
  return x * f;
}
struct graph {
  struct node {
    int to, nxt, cost;
  } sq[600600];
  int all, head[100100];
  long long dis[100100];
  bool vis[100100];
  void add(int u, int v, int w) {
    all++;
    sq[all].to = v;
    sq[all].nxt = head[u];
    sq[all].cost = w;
    head[u] = all;
  }
  void init() {
    all = 0;
    for (register int i = 1; i <= n; i++) head[i] = 0;
  }
  void dij() {
    memset(dis, 0x3f, sizeof(dis));
    memset(vis, 0, sizeof(vis));
    for (register int i = 1; i <= k; i++) {
      dis[i] = 0;
      q.push((hnode){i, 0});
    }
    while (!q.empty()) {
      int u = q.top().u;
      q.pop();
      if (vis[u]) continue;
      vis[u] = 1;
      for (int i = head[u]; i; i = sq[i].nxt) {
        int v = sq[i].to;
        if (dis[v] > dis[u] + sq[i].cost) {
          dis[v] = dis[u] + sq[i].cost;
          q.push((hnode){v, dis[v]});
        }
      }
    }
  }
} gr;
struct tree {
  struct node {
    int to, nxt, cost;
  } sq[600600];
  int all, head[100100], fa[100100][20], dep[100100];
  long long dis[100100][20];
  void init() {
    all = 0;
    memset(head, 0, sizeof(head));
    memset(dis, 0, sizeof(dis));
    memset(fa, 0, sizeof(fa));
  }
  void add(int u, int v, long long w) {
    all++;
    sq[all].to = v;
    sq[all].nxt = head[u];
    sq[all].cost = w;
    head[u] = all;
  }
  void dfs(int u, int fu) {
    dep[u] = dep[fu] + 1;
    fa[u][0] = fu;
    for (register int i = 1; i <= 19; i++) {
      fa[u][i] = fa[fa[u][i - 1]][i - 1];
      dis[u][i] = max(dis[u][i - 1], dis[fa[u][i - 1]][i - 1]);
    }
    for (int i = head[u]; i; i = sq[i].nxt) {
      int v = sq[i].to;
      if (v == fu) continue;
      dis[v][0] = sq[i].cost;
      dfs(v, u);
    }
  }
  long long query(int u, int v) {
    if (dep[u] < dep[v]) swap(u, v);
    long long ans = 0;
    int tmp = dep[u] - dep[v];
    for (register int i = 19; i >= 0; i--) {
      if ((tmp >> i) & 1) {
        ans = max(dis[u][i], ans);
        u = fa[u][i];
      }
    }
    if (u == v) return ans;
    for (register int i = 19; i >= 0; i--) {
      if (fa[u][i] != fa[v][i]) {
        ans = max(ans, max(dis[u][i], dis[v][i]));
        u = fa[u][i];
        v = fa[v][i];
      }
    }
    return max(ans, max(dis[u][0], dis[v][0]));
  }
} tr;
int main() {
  n = read();
  m = read();
  k = read();
  ask = read();
  gr.init();
  for (register int i = 1; i <= m; i++) {
    int u = read(), v = read(), w = read();
    gr.add(u, v, w);
    gr.add(v, u, w);
  }
  gr.dij();
  for (register int u = 1; u <= n; u++) {
    for (int i = gr.head[u]; i; i = gr.sq[i].nxt) {
      int v = gr.sq[i].to;
      if (u > v) continue;
      edge[++tot] = (edgenode){u, v, gr.dis[u] + gr.dis[v] + gr.sq[i].cost};
    }
  }
  sort(edge + 1, edge + 1 + tot);
  for (register int i = 1; i <= n; i++) pa[i] = i;
  tr.init();
  for (register int i = 1; i <= tot; i++) {
    int x = edge[i].u, y = edge[i].v;
    int fx = find(x), fy = find(y);
    if (fx != fy) {
      pa[fx] = fy;
      tr.add(x, y, edge[i].w);
      tr.add(y, x, edge[i].w);
    }
  }
  tr.dfs(1, 0);
  while (ask--) {
    int u = read(), v = read();
    printf("%lld\n", tr.query(u, v));
  }
  return 0;
}
