#include<bits/extc++.h>
#ifdef _debug 
#define dout(i) cout << #i << ' ' << i << ' '
#else 
#include<bits/stdc++.h>
#define dout(i) 0&&0
#endif
#pragma GCC optimize("unroll-loops,no-stack-protector,O3")
#define priority_queue __gnu_pbds::priority_queue
#define unordered_map __gnu_pbds::gp_hash_table
#define rep(_n) for(int __i = _n;__i--;)
#define rep0(_i, _n) for(int _i = 0; (_i)<(_n) ;++_i)
#define rep1(_i, _n) for(int _i = 1; (_i)<=(_n) ;++_i)
#define yn(i) ((i)?"Yes" : "No")
#define eout(i) {cout << (i) << '\n';exit(0);}
#define rout(i) {return cout << (i) << '\n', 0;}
#define multi int _T;for(cin >> _T;_T--;)
using namespace std;
using ll = long long;using ull = unsigned long long;using ul = unsigned;using db = double;
using __gnu_pbds::null_type;
#define getchar_unlocked  _getchar_nolock
inline void read(char &a){static char p; while(isspace(p = getchar_unlocked())); a = p; }
inline void read(string &a){static char p; while(isspace(p = getchar_unlocked())); a = p; while(!isspace(p = getchar_unlocked()))a.push_back(p);}
template<typename T> inline void read(T& a){static char p; static bool b; while (!isdigit(p = getchar_unlocked()))b = p == '-'; a = p ^ '0'; while (isdigit(p = getchar_unlocked())) a *= 10, a += p ^ '0'; if(b)a *= -1; }
template<typename T> inline void read(T begin, const T &end){while(begin != end)read(*begin), ++begin;}
template<typename T> inline void write(T begin, const T &end){while(begin != end)cout << *begin << " \n"[next(begin) == end], ++begin;}
template<typename T> using rbtree = __gnu_pbds::tree<T,__gnu_pbds::null_type,less<T>,__gnu_pbds::rb_tree_tag,__gnu_pbds::tree_order_statistics_node_update>;
template<typename T> inline ostream& operator << (ostream &ou, const vector<T> &a){for(auto it = a.begin();it != a.end();++it)ou << (it != a.begin() ? " " : "") << *it;return ou;}
template<typename T1, typename T2>inline istream& operator >> (istream &in, pair<T1, T2> &a){return in >> a.first >> a.second;}
template<typename T1, typename T2>inline ostream& operator << (ostream &ou, const pair<T1, T2> &b){return ou << b.first << ' ' << b.second;}
template<typename T> inline long long pow(long long v, long long t, const T &p){long long res = 1;for(;t;t >>= 1, v = v * v % p)if(t & 1)res = res * v % p;return res;}
const int maxn = 300010;
int n, m, k, q;
vector<pair<int,int>> edge[maxn];
vector<pair<ll, pair<int,int>> > mst;
ll dis[maxn];
const ll inf = 1ll<<59;
int mo[maxn], ml;
void dij(int s){
	priority_queue<pair<int,int>, greater<pair<int,int>> > togo;
	static int vis[maxn];
	for(const auto [id, w] : edge[s]){
		dis[id] = w;
		togo.push({w, id});
	}
	vis[s] = s;
	// dout(s);
	while(togo.size()){
		int id;ll w;
		tie(w, id) = togo.top();
		// dout(id), dout(w)<<'\n';
		togo.pop();
		if(vis[id] != s){
			mo[ml++] = id;
			vis[id] = s;
			dis[id] = w;
			if(id <= k)mst.push_back({w, {s, id}});
			else for(const auto [id, ew] : edge[id])if(vis[id] != s and dis[id] > w + ew){
				dis[id] = w + ew;
				togo.push({w+ew, id});
			}
		}
	}
	rep0(i, ml)dis[i] = inf;
	ml = 0;
}
int g[maxn];
int find(int i){
	return i == g[i] ? i : g[i] = find(g[i]);
}
const int maxk = 18;
ll dp[maxk][maxn];
int anc[maxk][maxn];
int in[maxn], out[maxn], dep[maxn];
bool isanc(int a, int b){
	return in[a] <= in[b] and out[a] >= out[b];
}

void dfs(int now, int last = 1, ll lw = 0){
	static int t;
	static int d;
	dep[now] = ++d;
	in[now] = ++t;
	anc[0][now] = last;
	dp[0][now] = lw;

	// dout(now), dout(last)<<'\n';

	rep1(i, maxk-1){
		anc[i][now] = anc[i-1][ anc[i-1][now] ];
		dp[i][now] = max(dp[i-1][now], dp[i-1][ anc[i-1][now] ]);
	}
	for(const auto &[id, w] : edge[now])if(id != last){
		dfs(id,  now, w);
	}
	out[now] = t;
	--d;
}
ll query(int a, int b){
	if(dep[a] > dep[b])swap(a, b);
	ll res = 0;
	for(int i = maxk-1;i >= 0;--i)if(!isanc(anc[i][b], a)){
		res = max(res, dp[i][b]);
		b = anc[i][b];
	}
	res = max(res, dp[0][b]);
	b = anc[0][b];
	if(b == a)return res;
	swap(a, b);
	for(int i = maxk-1;i >= 0;--i)if(!isanc(anc[i][b], a)){
		res = max(res, dp[i][b]);
		b = anc[i][b];
	}
	res = max(res, dp[0][b]);
	return res;
}
void build(){
	sort(mst.begin(), mst.end());
	for(auto &i : mst){
		if(find(i.second.second) != find(i.second.first)){
			edge[i.second.first].emplace_back(i.second.second, i.first);
			edge[i.second.second].emplace_back(i.second.first, i.first);
			g[find(i.second.second)] = find(i.second.first);
		}
	}
	dfs(1);
}
signed main(){
	ios_base::sync_with_stdio(0), cin.tie(0);
	read(n), read(m), read(k), read(q);
	rep(m){
		int a, b, w;
		read(a), read(b), read(w);
		edge[a].emplace_back(b, w), edge[b].emplace_back(a, w);
	}	
	rep1(i, n)dis[i] = inf;
	rep1(i, k)dij(i), g[i] = i;

	// for(auto u : mst)cout << u << '\n';

	rep1(i, n)edge[i].clear();
	build();
	rep(q){
		int a, b;
		read(a), read(b);
		cout << query(a, b) << '\n';
	}
}