#include <iostream>
#include <vector>
#include <string>
#include <cassert>
#include <cstring>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <algorithm>
#include <map>
#include <cmath>
#include <numeric>
#include <functional>
#include <ctime>
#include <unordered_map>
#include <sstream>

using namespace std;
typedef long long Long;
typedef long double Double;
typedef vector<int> VI;
typedef vector<VI> VVI;
typedef pair<int,int> PII;
typedef pair<Long,Long> PLL;

int read(int &x) { return scanf("%d", &x); }
int read(int &x, int &y) { return scanf("%d%d", &x, &y); }
int read(int &x, int &y, int &z) { return scanf("%d%d%d", &x, &y, &z); }
int read(Long &x) { return scanf("%lld", &x); }
int read(Long &x, Long &y) { return scanf("%lld%lld", &x, &y); }
int read(double &x) { return scanf("%lf", &x); }
char buff[2000010];
int read(string &s) { int r = scanf("%s", buff); s = buff; return r; }

#define dlog2(n) ((n) == -1 ? 0 : (31-__builtin_clz(n)))

#define sz(a) int(a.size())

struct Edge {
	int u, v;
	Long w;
	int getV(int _u) {
		return _u == u ? v : u;
	}
};

struct DisjointSet
{
	vector<int> P; // if < 0 then negative size, else parentId
	DisjointSet(int N) : P(N, -1) {}
	int find(int x) {
		return P[x] < 0 ? x : (P[x] = find(P[x]));
	}
	bool join(int x,int y) {
		if((x = find(x)) == (y = find(y))) return false;
		if(P[y] < P[x]) swap(x,y);
		P[x] += P[y];
		P[y] = x;
		return true;
	}
};

vector<Long> ditra(int K, vector<Edge> &E, VVI &adj) {
	vector<Long> D = vector<Long>(adj.size(), 1000000000000000000LL);
	priority_queue<pair<Long,int>> PQ;
	for (int i = 0; i < K; ++i) {
		D[i] = 0;
		PQ.push(pair<Long, int>(0, i));
	}
	while (PQ.size()) {
		auto t = PQ.top(); PQ.pop();
		Long d = -t.first;
		int u = t.second;
		if (D[u] < d) continue;
		for (int ei : adj[u]) {
			Edge &e = E[ei];
			int v = e.getV(u);
			Long nd = d + e.w;
			if (nd < D[v]) {
				D[v] = nd;
				PQ.push(make_pair(-nd, v));
			}
		}
	}
	return D;
}

int main() {

	int N, M, K, Q;
	read(N, M);
	read(K, Q);
	vector<Edge> E(M);
	VVI adj(N);
	for (int i = 0; i < M; ++i) {
		read(E[i].u, E[i].v);
		read(E[i].w);
		E[i].u--;
		E[i].v--;
		adj[E[i].u].push_back(i);
		adj[E[i].v].push_back(i);
	}
	vector<Long> D = ditra(K, E, adj);
	for (auto &e : E) {
		e.w += D[e.v] + D[e.u];
	}
	sort(E.begin(), E.end(), [](auto a, auto b){ return a.w < b.w; });
	DisjointSet DS(N);
	vector<set<int>> QE(N);
	for (int i = 0; i < Q; ++i) {
		int u, v;
		read(u, v); u--;v--;
		QE[u].insert(i);
		QE[v].insert(i);
	}
	VI ANS(Q);
	for (int i = 0; i < E.size(); ++i) {
		int ru = DS.find(E[i].u), rv = DS.find(E[i].v);
		if  (ru == rv) continue;
		DS.join(ru, rv);
		int rr = DS.find(ru);
		if (rr != ru) swap(ru, rv);
		// ru is the parent
		for (int q : QE[rv]) {
			if (QE[ru].count(q) == 0) {
				QE[ru].insert(q);
			} else {
				QE[ru].erase(q);
				ANS[q] = E[i].w;
			}
		}
	}
	for (int i = 0; i < Q; ++i) {
		cout << ANS[i] << endl;
	}


}






















