#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
#define _for(i,a,b) for(register int i = (a);i < b;i ++)
#define _rep(i,a,b) for(register int i = (a);i > b;i --)
#define INF 0x3f3f3f3f3f3f3f3f
#define pb push_back
//������
#define maxn 100003
//������
#define maxe 600003
int k, q;
struct G
{
	int n,m;
	//�洢ĳһ���ߵĺ�һ����
	int Next[maxe];
	//�洢�ߵ���ʼ��Ϣ������x ->(w) y����head[x]Ϊ��һ������ߵı��
	int head[maxn];
	//�洢�ߵĵ�����Ϣ ���� x ->(w) y�е�y
	int ver[maxe];
	//�洢�ߵ�Ȩֵ��Ϣ ���� x ->(w) y�е�w
	ll val[maxe];
	//����ߵ�����
	int tot;
	void add(int x,int y,int w)
	{
		ver[++tot] = y,Next[tot] = head[x],head[x] = tot,val[tot] = w;
	}
} g,MSTg;

struct Djs
{
	int par[maxn];
	int high[maxn];
	Djs()
	{
		_for(i,1,maxn)
		{
			par[i] = i;
			high[i] = 0;
		}
	}
	int find(int x)
	{
		//·��ѹ��
		return par[x] == x ? x : par[x] = find(par[x]);
	}
	void unite(int x,int y)
	{
		x = find(x);
		y = find(y);
		if(x==y) return ;
		//���Ⱥϲ�
		if(high[x]<high[y])
			par[x] = y;
		else
		{
			par[y] = x;
			if(high[x]==high[y])
				high[x] ++;
		}
	}
	bool same(int x,int y)
	{
		return find(x) == find(y);
	}
} MSTd1;

struct Kruskal
{
	struct edge
	{
		int u;
		int v;
		ll w;
		bool operator < (edge b)
		{
			return w < b.w;
		}
	};
	//��Ҫ�õ��ı�����
	vector<edge> e;
	//��С������Ȩֵ��
	ll MSTval;
	void kruskal(const G &g)
	{
		//�����б߼�����ʱ���鲢���ձ�Ȩ��С��������
		_for(x,1,g.n+1)
		for(int i = g.head[x]; i; i = g.Next[i])
			e.pb({x,g.ver[i],g.val[i]});
		sort(e.begin(),e.end());
		//�������бߣ������ߵ�����δ��ͨ���򽫸ñ߼�����С������
		_for(i,0,e.size())
		if(!MSTd1.same(e[i].u,e[i].v))
		{
			if(!e[i].u || !e[i].v)
				continue;
			MSTg.add(e[i].u,e[i].v,e[i].w);
			MSTg.add(e[i].v,e[i].u,e[i].w);
			MSTd1.unite(e[i].u,e[i].v);
			MSTval += e[i].w;
		}
		MSTg.n = g.n;
		MSTg.m = g.n-1;
	}
} k1;

struct Dij
{
	//first ����̾��룬second �Ƕ�����
	typedef pair<int,int> P;
	//��������
	ll d[maxn];
	//�Ƿ�ʹ�ù���
	int vis[maxn];
	priority_queue<P,vector<P>,greater<P>> q;
	// s -> other v
	int s;
	void dij(int s,const G &g)
	{
		//d��ʼ��
		_for(i,1,g.n+1)
		d[i] = INF;
		d[s] = 0;
		//������
		q.push(P {0,s});
		while(!q.empty())
		{
			//��ȡd��С�ĵ�
			P p = q.top();
			q.pop();
			int x = p.second;
			if(vis[x]) continue;
			vis[x] = 1;
			//ʹ��x���µ����������
			for(int i = g.head[x]; i; i = g.Next[i])
			{
				int y = g.ver[i];
				int w = g.val[i];
				if(d[y] > d[x] + w)
				{
					d[y] = d[x] + w;
					q.push(P {d[y],y});
				}
			}
		}
	}
} d1;
struct BitIn
{
	//f[x][k]��ʾx������2^k
	int f[maxn][30];
	//������飬���ڵ����Ϊ1
	int d[maxn];
	//dist[x]��ʾ���ڵ㵽�ڵ�x�ľ���
	ll dist[maxn][30];
	//����������Ϊ2^bitmaxd
	int bitmaxd;
	//Ԥ����
	void bfsInit(const G &g,int st)
	{
		//��Ҫ�õ�����ʱ����
		memset(dist,0,sizeof(dist));
		queue<int> q;
		//���ڵ����Ϊ1��bitmaxd = log2��n nΪ�ڵ�����
		q.push(st);
		d[st] = 1;
		bitmaxd = (int)(log(g.n)/log(2)) + 1;
		while(!q.empty())
		{
			int x = q.front();
			q.pop();
			for(int i = g.head[x]; i; i = g.Next[i])
			{
				int y = g.ver[i];
				//d[y]�����¹�˵��y��x�İְ֣��Թ�
				if(d[y])
					continue;
				//���+1
				d[y] = d[x] + 1;
				//y�İְ���x
				f[y][0] = x;
				dist[y][0] = g.val[i];
			//	printf("%d->%d %lld\n",x,g.ver[i],g.val[i]);
				//����y����������
				_for(j,1,bitmaxd+1)
				{
					f[y][j] = f[f[y][j-1]][j-1];
					dist[y][j] = max(dist[y][j-1],dist[f[y][j-1]][j-1]);
				}
				q.push(y);
			}
		}
	}
	ll query(int x,int y)
	{
		ll ans = 0;
		//ȷ�� d[x]��d[y]
		if(d[x]<d[y])
			swap(x,y);
		//��x�������y��ͬ
		_rep(i,bitmaxd,-1)
		if(d[f[x][i]] >= d[y])
			ans = max(ans,dist[x][i]),x = f[x][i];
		//��x==y��x��y��һ�����ϣ�˵��LCA(x,y)=y
		if(x==y) return ans;
		//����x��yһ������LCA(x,y)�Ķ��ӽڵ�
		_rep(i,bitmaxd,-1)
		if(f[x][i] != f[y][i])
		{
			ans = max(ans,dist[x][i]);
			ans = max(ans,dist[y][i]);
			x = f[x][i],y = f[y][i];
		}
		
		return max(ans,max(dist[x][0],dist[y][0]));
	}
} b1;
int main()
{
	scanf("%d%d%d%d",&g.n,&g.m,&k,&q);
	_for(i,0,g.m)
	{
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z);
		g.add(x,y,z);
		g.add(y,x,z);
	}
	_for(i,1,k+1)
	g.add(0,i,0),g.add(i,0,0);

	d1.dij(0,g);
	_for(x,1,g.n+1)
	for(int i = g.head[x]; i; i = g.Next[i])
		g.val[i] += d1.d[x]+d1.d[g.ver[i]];

	k1.kruskal(g);
	b1.bfsInit(MSTg,1);
//	printf("%lld\n",b1.dist[2][0]);
//	printf("%lld\n",b1.dist[4][0]);
	while(q--)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		printf("%lld\n",b1.query(x,y));
	}
	return 0;
}
