#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
const int M = 3e5 + 10;
const int mod = 1e9 + 7;
const long long inf = 1e12;
struct edge {
  int to, w, u;
  friend bool operator<(edge a, edge b) { return a.w < b.w; }
} e, a[M], ee[M];
struct heapnode {
  int x;
  long long dis;
  heapnode(int _x, long long _dis) : x(_x), dis(_dis) {}
  friend bool operator<(heapnode a, heapnode b) { return a.dis > b.dis; }
};
vector<edge> g[N], tr[N];
void addadge(int u, int v, int w) {
  e.to = v;
  e.w = w;
  g[u].push_back(e);
}
int n, k, m, q;
long long dis[N];
int fc[N], vis[N];
void dijkstra() {
  priority_queue<heapnode> q;
  for (int i = 1; i <= n; i++) dis[i] = inf, vis[i] = 0;
  for (int i = 1; i <= k; i++) {
    dis[i] = 0;
    fc[i] = i;
    q.push(heapnode(i, 0));
  }
  while (!q.empty()) {
    int x = q.top().x;
    int d = q.top().dis;
    q.pop();
    if (vis[x]) continue;
    vis[x] = 1;
    for (int i = 0; i < g[x].size(); i++) {
      int to = g[x][i].to;
      int w = g[x][i].w;
      if (dis[to] > dis[x] + w) {
        dis[to] = dis[x] + w;
        fc[to] = fc[x];
        q.push(heapnode(to, dis[to]));
      }
    }
  }
}
int father[N], deep[N];
int fa[N][18], fm[N][18];
int find(int x) { return father[x] == x ? x : find(father[x]); }
void addtree(int u, int v, int w) {
  e.to = v;
  e.w = w;
  tr[u].push_back(e);
}
void dfs(int x, int f) {
  for (int i = 1; i <= 17; i++) {
    fa[x][i] = fa[fa[x][i - 1]][i - 1];
    fm[x][i] = max(fm[x][i - 1], fm[fa[x][i - 1]][i - 1]);
  }
  for (int i = 0; i < tr[x].size(); i++) {
    int to = tr[x][i].to;
    if (to == f) continue;
    fa[to][0] = x;
    fm[to][0] = tr[x][i].w;
    deep[to] = deep[x] + 1;
    dfs(to, x);
  }
}
void build() {
  for (int i = 1; i <= m; i++) {
    int u = fc[a[i].u];
    int to = fc[a[i].to];
    int w = dis[a[i].u] + dis[a[i].to] + a[i].w;
    ee[i].u = u, ee[i].to = to, ee[i].w = w;
  }
  int trnum = 0;
  sort(ee + 1, ee + 1 + m);
  for (int i = 1; i <= k; i++) father[i] = i;
  for (int i = 1; i <= m; i++) {
    int x = find(ee[i].u);
    int y = find(ee[i].to);
    if (x != y) {
      ++trnum;
      father[x] = y;
      addtree(ee[i].u, ee[i].to, ee[i].w);
      addtree(ee[i].to, ee[i].u, ee[i].w);
    }
    if (trnum == k - 1) break;
  }
  dfs(1, -1);
}
int lca(int u, int v) {
  int res = 0;
  if (u == v) return res;
  if (deep[u] < deep[v]) swap(u, v);
  for (int i = 17; i >= 0; i--)
    if (deep[fa[u][i]] >= deep[v]) {
      res = max(res, fm[u][i]);
      u = fa[u][i];
    }
  if (u == v) return res;
  for (int i = 17; i >= 0; i--)
    if (fa[u][i] != fa[v][i]) {
      res = max(res, max(fm[v][i], fm[u][i]));
      u = fa[u][i];
      v = fa[v][i];
    }
  res = max(res, max(fm[v][0], fm[u][0]));
  return res;
}
int main() {
  scanf("%d%d%d%d", &n, &m, &k, &q);
  for (int i = 1; i <= m; i++) {
    scanf("%d%d%d", &a[i].u, &a[i].to, &a[i].w);
    addadge(a[i].u, a[i].to, a[i].w);
    addadge(a[i].to, a[i].u, a[i].w);
  }
  dijkstra();
  build();
  for (int i = 1; i <= q; i++) {
    int u, v;
    scanf("%d%d", &u, &v);
    printf("%d\n", lca(u, v));
  }
}
