#include <bits/stdc++.h>
#define maxn 300030
using namespace std;
typedef long long LL;
typedef pair<LL, int> PLI;
LL inf = 1LL << 60;
vector<LL> dist(maxn, inf);
vector<LL> val(maxn);
int n, m, k, q, x, y;
LL w, res;
vector<PLI> graph[maxn];

struct edge{
	int from, to; LL w;
	bool operator < (const edge& b){
		return w < b.w;
	}
} e[maxn];

struct Kruskal{
	vector<int> par, sz;
	
	int find(int x){
		return (par[x] == x ? par[x] : find(par[x]));
	}
	
	void merge(int x, int y, LL c){
		x = find(x);
		y = find(y);
		if (sz[x] > sz[y]) swap(x, y);
		par[x] = y;
		sz[y] = max(sz[y], sz[x] + 1);
		val[x] = c;
	}
	
	void init(){
		for (int i = 0; i <= n; i ++) par.push_back(i);
		sz.assign(n + 1, 1);
		sort(e, e + m);
		for (int i = 0; i < m; i ++){
			int to = e[i].to;
			int from = e[i].from;
			LL w = e[i].w;
			merge(to, from, w);
		}
	}
	
	int query(int u, int v){
		LL res = 0;
		for (; u != v; u = par[u]){
			if (sz[u] > sz[v]) swap(u, v);
			res = max(res, val[u]);
	    }
	    return res;
	}
};

void dijkstra(){
	priority_queue<PLI, vector<PLI>, greater<PLI> > pq;
	for (int i = 1; i <= k; i ++){
		pq.push(make_pair(0, i));
		dist[i] = 0;
	}
	while(! pq.empty()){
		PLI p = pq.top();
		pq.pop();
		LL d = p.first;
		int x = p.second;
		for (int i = 0; i < graph[x].size(); i ++){
			PLI to = graph[x][i];
			if (d + to.first < dist[to.second]){
				dist[to.second] = d + to.first;
				pq.push(make_pair(dist[to.second], to.second));
			}
		}
	}
}

int main(){
	scanf("%d%d%d%d", &n, &m, &k, &q);
	for (int i = 0; i < m; i ++){
		scanf("%d%d%lld", &x, &y, &w);
		graph[x].push_back(make_pair(w, y));
		graph[y].push_back(make_pair(w, x));
		e[i] = (edge){x, y, w};
	}
	dijkstra();
	for (int i = 0; i < m; i ++){
		e[i].w += dist[e[i].to] + dist[e[i].from];
	}
	Kruskal K;
	K.init();
	while(q --){
		scanf("%d%d", &x, &y);
		res = K.query(x, y);
		printf("%lld\n", res);
	}
}
