#include <bits/stdc++.h>
using namespace std;
template <class T>
bool ckmin(T& a, const T& b) {
  return b < a ? a = b, 1 : 0;
}
template <class T>
bool ckmax(T& a, const T& b) {
  return a < b ? a = b, 1 : 0;
}
template <int SZ>
struct DSU {
  int par[SZ];
  int size[SZ];
  DSU() {
    for (int i = 0; i < SZ; i++) par[i] = i, size[i] = 1;
  }
  int get(int node) {
    if (par[node] != node) par[node] = get(par[node]);
    return par[node];
  }
  bool connected(int n1, int n2) { return (get(n1) == get(n2)); }
  void unite(int n1, int n2) {
    n1 = get(n1);
    n2 = get(n2);
    if (n1 == n2) return;
    if (rand() % 2) {
      par[n1] = n2;
      size[n2] += size[n1];
    } else {
      par[n2] = n1;
      size[n1] += size[n2];
    }
  }
};
template <int SZ>
struct tree {
  vector<pair<int, long long>> adj[SZ];
  const static int LGSZ = 32 - __builtin_clz(SZ - 1);
  pair<int, long long> ppar[SZ][LGSZ];
  int depth[SZ];
  void addEdge(int u, int v, int d) {
    adj[u].push_back(make_pair(v, d));
    adj[v].push_back(make_pair(u, d));
  }
  void dfs(int u, int dep) {
    depth[u] = dep;
    for (auto v : adj[u])
      if (ppar[u][0].first != v.first) {
        ppar[v.first][0] = make_pair(u, v.second);
        dfs(v.first, dep + 1);
      }
  }
  void build() {
    ppar[0][0] = make_pair(0, 0);
    for (int i = 0; i < SZ; i++) depth[i] = 0;
    dfs(0, 0);
    for (int i = 1; i < LGSZ; i++)
      for (int j = 0; j < SZ; j++) {
        ppar[j][i].first = ppar[ppar[j][i - 1].first][i - 1].first;
        ppar[j][i].second = max(ppar[j][i - 1].second,
                                ppar[ppar[j][i - 1].first][i - 1].second);
      }
  }
  long long getmax(int u, int v) {
    if (depth[u] < depth[v]) swap(u, v);
    long long res = 0;
    for (int i = (LGSZ)-1; i >= 0; i--)
      if (depth[ppar[u][i].first] >= depth[v]) {
        ckmax(res, ppar[u][i].second);
        u = ppar[u][i].first;
      }
    if (u == v) return res;
    for (int i = (LGSZ)-1; i >= 0; i--) {
      if (ppar[u][i].first != ppar[v][i].first) {
        ckmax(res, ppar[u][i].second);
        u = ppar[u][i].first;
        ckmax(res, ppar[v][i].second);
        v = ppar[v][i].first;
      }
    }
    ckmax(res, ppar[u][0].second);
    ckmax(res, ppar[v][0].second);
    return res;
  }
};
const int MAX_N = 200010;
int n, m, k, q;
vector<pair<int, long long>> adj[MAX_N];
bool vis[MAX_N];
long long d[MAX_N];
DSU<MAX_N> dsu;
tree<MAX_N> tr;
int main() {
  ios::sync_with_stdio(0);
  cin.tie(0);
  cin >> n >> m >> k >> q;
  for (int i = 0; i < m; i++) {
    int u, v;
    long long w;
    cin >> u >> v >> w;
    u--;
    v--;
    adj[u].push_back(make_pair(v, w));
    adj[v].push_back(make_pair(u, w));
  }
  for (int i = 0; i < n; i++) d[i] = 1e18;
  priority_queue<pair<long long, int>, vector<pair<long long, int>>,
                 greater<pair<long long, int>>>
      pq;
  for (int i = 0; i < k; i++) {
    d[i] = 0;
    pq.push(make_pair(0, i));
  }
  while (!pq.empty()) {
    pair<long long, int> t = pq.top();
    pq.pop();
    if (vis[t.second]) continue;
    vis[t.second] = 1;
    for (auto v : adj[t.second]) {
      if (ckmin(d[v.first], d[t.second] + v.second)) {
        pq.push(make_pair(d[v.first], v.first));
      }
    }
  }
  vector<pair<long long, pair<int, int>>> edges;
  for (int u = 0; u < n; u++) {
    for (auto v : adj[u])
      if (v.first > u) {
        edges.push_back(
            make_pair(v.second + d[u] + d[v.first], make_pair(u, v.first)));
      }
  }
  sort(edges.begin(), edges.end());
  for (int i = 0; i < (int)edges.size(); i++) {
    if (!dsu.connected(edges[i].second.first, edges[i].second.second)) {
      dsu.unite(edges[i].second.first, edges[i].second.second);
      tr.addEdge(edges[i].second.first, edges[i].second.second, edges[i].first);
    }
  }
  tr.build();
  for (int i = 0; i < q; i++) {
    int a, b;
    cin >> a >> b;
    a--;
    b--;
    cout << tr.getmax(a, b) << "\n";
  }
}
