#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
const int maxm = 3e5 + 5;
int n, m, K, Q;
inline int read() {
  char ch = getchar();
  int sum = 0;
  int f = 1;
  while (!isdigit(ch)) f = ch == '-' ? -1 : 1, ch = getchar();
  while (isdigit(ch)) sum = sum * 10 + ch - '0', ch = getchar();
  return sum * f;
}
namespace Graph {
struct Node {
  int to;
  int next;
  long long w;
} edge[maxn << 1];
int head[maxn], cnt;
inline void add(int x, int y, int w) {
  edge[++cnt].next = head[x];
  edge[cnt].to = y;
  edge[cnt].w = w;
  head[x] = cnt;
}
}  // namespace Graph
using namespace Graph;
struct Edge {
  int x;
  int y;
  long long w;
} e[maxn << 1];
struct Point {
  int x;
  long long d;
  bool operator<(const Point &tmp) const { return tmp.d < d; }
};
int v[maxn];
long long dis[maxn];
priority_queue<Point> q;
inline void Dijkstra() {
  for (int i = 1; i <= n; i++)
    if (i <= K) {
      q.push((Point){i, 0});
      dis[i] = 0;
    } else
      dis[i] = 1e18;
  while (!q.empty()) {
    int x = q.top().x;
    q.pop();
    if (v[x]) continue;
    v[x] = 1;
    for (int i = head[x]; i != 0; i = edge[i].next) {
      int k = edge[i].to;
      int w = edge[i].w;
      if (v[k]) continue;
      if (dis[k] > dis[x] + w) {
        dis[k] = dis[x] + w;
        q.push((Point){k, dis[k]});
      }
    }
  }
}
inline bool cmp(const Edge &x, const Edge &y) { return x.w < y.w; }
pair<int, int> query[maxm];
long long ans[maxm];
vector<int> res[maxn];
int ma[maxm << 1];
namespace Union_Set {
int f[maxn];
int siz[maxn];
inline int find(int x) {
  if (f[x] == x)
    return x;
  else
    return f[x] = find(f[x]);
}
inline void merge(int x, int y, int c) {
  x = find(x);
  y = find(y);
  if (x == y) return;
  if (siz[x] > siz[y]) swap(x, y);
  for (int i = 0; i < res[x].size(); i++) {
    int tmp = res[x][i];
    int idx = tmp ^ 1;
    if (find(ma[idx]) == y) {
      ans[tmp / 2] = c;
    }
    res[y].push_back(tmp);
  }
  res[x].clear();
  siz[y] += siz[x];
  f[x] = y;
}
}  // namespace Union_Set
using namespace Union_Set;
int main() {
  n = read();
  m = read();
  K = read();
  Q = read();
  for (int i = 1; i <= m; i++) {
    e[i].x = read();
    e[i].y = read();
    e[i].w = read();
    add(e[i].x, e[i].y, e[i].w);
    add(e[i].y, e[i].x, e[i].w);
  }
  Dijkstra();
  for (int i = 1; i <= m; i++) e[i].w = dis[e[i].x] + dis[e[i].y] + e[i].w;
  sort(e + 1, e + 1 + m, cmp);
  for (int i = 1; i <= n; i++) f[i] = i, siz[i] = 1;
  for (int i = 1; i <= Q; i++) {
    query[i].first = read();
    query[i].second = read();
    res[query[i].first].push_back(2 * i);
    res[query[i].second].push_back(2 * i + 1);
    ma[2 * i] = query[i].first;
    ma[2 * i + 1] = query[i].second;
  }
  for (int i = 1; i <= m; i++) merge(e[i].x, e[i].y, e[i].w);
  for (int i = 1; i <= Q; i++) printf("%lld\n", ans[i]);
  return 0;
}
