#include <bits/stdc++.h>
using namespace std;
const int N = 3e5 + 7;
int n, m, k, q;
vector<pair<int, long long> > adj[N], lst_tree[N];
long long ans[N];
long long d[N];
bool vis[N], viz[N], viq[N];
long long wei[N];
long long val[N];
map<pair<int, int>, long long> mps;
vector<pair<int, int> > qrs;
struct DSU {
  vector<int> fat;
  void init(int n) {
    fat.resize(n);
    for (int i = 0; i < n; i++) {
      fat[i] = i;
    }
  }
  int fin(int x) { return fat[x] = (fat[x] == x ? x : fin(fat[x])); }
  void unio(int a, int b) {
    int aa = fin(a);
    int bb = fin(b);
    if (aa < bb) swap(aa, bb);
    if (aa != bb) {
      fat[aa] = bb;
    }
  }
  bool same(int A, int B) { return fin(A) == fin(B); }
} dsu, dsq, dsr;
void addE(int u, int v, int w) {
  lst_tree[u].push_back({v, w});
  lst_tree[v].push_back({u, w});
}
void dijkstra() {
  memset(d, -1, sizeof d);
  priority_queue<pair<long long, int> > qu;
  for (int i = 1; i <= k; i++) {
    qu.push({0ll, i});
    d[i] = 0;
  }
  while (qu.size()) {
    pair<long long, int> tp = qu.top();
    qu.pop();
    long long dst = -tp.first;
    int node = tp.second;
    if (viz[node]) continue;
    viz[node] = 1;
    for (auto u : adj[node]) {
      if (d[u.first] == -1 || dst + u.second < d[u.first]) {
        d[u.first] = dst + u.second;
        dsu.unio(u.first, node);
        qu.push({-d[u.first], u.first});
      }
    }
  }
}
long long lift[N][25], lval[N][25];
int lw[N], up[N];
int t;
void dfs(int x, int p) {
  lw[x] = ++t;
  lift[x][0] = p;
  for (int i = 1; i < 25; i++) {
    lift[x][i] = lift[lift[x][i - 1]][i - 1];
    lval[x][i] = max(lval[x][i - 1], lval[lift[x][i - 1]][i - 1]);
  }
  for (auto u : lst_tree[x]) {
    if (u.first == p) continue;
    lval[u.first][0] = u.second;
    dfs(u.first, x);
  }
  up[x] = ++t;
}
bool upper(int u, int v) { return lw[v] >= lw[u] && up[v] <= up[u]; }
long long lca(int u, int v) {
  if (upper(u, v)) return u;
  if (upper(v, u)) return v;
  for (int i = 24; i >= 0; i--) {
    if (upper(lift[u][i], v)) continue;
    u = lift[u][i];
  }
  return lift[u][0];
}
long long get(int u, int v) {
  if (u == v) return 0;
  long long ret = 0;
  for (int i = 24; i >= 0; i--) {
    if (upper(lift[u][i], v)) continue;
    ret = max(ret, lval[u][i]);
    u = lift[u][i];
  }
  ret = max(ret, lval[u][0]);
  return ret;
}
long long query(int u, int v) {
  int LCA = lca(u, v);
  return max(get(u, LCA), get(v, LCA));
}
int main() {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  cin >> n >> m >> k >> q;
  dsu.init(n + 10);
  dsq.init(n + 10);
  dsr.init(n + 10);
  for (int i = 0; i < m; i++) {
    int u, v, w;
    cin >> u >> v >> w;
    adj[u].push_back({v, w});
    adj[v].push_back({u, w});
  }
  for (int i = 0; i < q; i++) {
    int u, v;
    cin >> u >> v;
    qrs.push_back({u, v});
  }
  for (int i = 1; i <= n; i++) {
    sort(adj[i].begin(), adj[i].end(),
         [&](pair<int, int> p1, pair<int, int> p2) {
           if (p1.second == p2.second) return p1 < p2;
           return p1.second < p2.second;
         });
  }
  dijkstra();
  for (int i = 1; i <= n; i++) {
    for (auto u : adj[i]) {
      int U = dsu.fin(u.first);
      int V = dsu.fin(i);
      if (U != V) {
        if (!mps[{U, V}] || u.second + d[i] + d[u.first] < mps[{U, V}]) {
          mps[{U, V}] = mps[{V, U}] = u.second + d[i] + d[u.first];
        }
      }
    }
  }
  vector<pair<long long, pair<int, int> > > vie;
  for (auto u : mps) {
    vie.push_back({u.second, u.first});
  }
  sort(vie.begin(), vie.end());
  for (auto u : vie) {
    if (dsq.same(u.second.first, u.second.second)) continue;
    addE(u.second.first, u.second.second, u.first);
    dsq.unio(u.second.first, u.second.second);
  }
  dfs(1, 1);
  for (auto u : qrs) {
    cout << query(u.first, u.second) << "\n";
  }
  return 0;
}
