#include <bits/stdc++.h>

using namespace std;

const int N = 3e2 + 10;

#define pii pair<int, int>
#define PB push_back

int n, cnt;
vector<pii> ans;
int d[N];

void dfs(int l, int r, int x) {
    if (r < l) {
        cnt++;
        return;
    }
    else if (r - l == 0) {
        int st = cnt + 1;
        for (int i = st; i <= st + d[l] - x; ++i) {
            for (int j = st; j < i; ++j) {
                ans.PB(pii(j, i));
                //printf("%d %d\n", i, j);
            }
        }
        cnt += d[l] - x + 1;
        return;
    }
    else {
        dfs(l + 1, r - 1, d[l]);
        //printf("%d %d\n", cnt, d[r] - d[r - 1]);
        cnt += d[r] - d[r - 1];
        for (int i = 1; i <= cnt; ++i)
            for (int j = cnt + 1; j <= cnt + d[l] - x; ++j) {
                ans.PB(pii(i, j));
            }
        for (int j = cnt + 1; j <= cnt + d[l] - x; ++j) {
            for (int k = cnt + 1; k < j; ++k)
                ans.PB(pii(k, j));
        }
        cnt += d[l] - x;
    }
}

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) scanf("%d", &d[i]);
    dfs(1, n, 0);
    //printf("%d\n", cnt);
    printf("%d\n", ans.size());
    for (int i = 0; i < ans.size(); ++i)
        printf("%d %d\n", ans[i].first, ans[i].second);
    return 0;
}


#include<algorithm>
#include<set>
#include<queue>
#include<time.h>
#include<vector>
#include<stdio.h>
#include<ctype.h>
#include<iostream>
#include<string.h>
#include<string>
#include<map>
using namespace std;
#define lson(x) (x<<1)
#define rson(x) ((x<<1)|1)
typedef long long lld;
const int MAX = 210000;
const int INF = 1000000000;
const int MOD=1000000007;
lld mod(lld a,lld b,lld m){
    lld ret=1;
    a%=m;
    while(b){
        if(b&1)ret=ret*a%m;
        b>>=1;
        a=a*a%m;
    }
    return ret;
}
lld inv(lld a){
    return mod(a,MOD-2,MOD);
}

lld vabs(lld x){
    return x>0?x:-x;
}
lld gcd(lld a,lld b){
    return a%b?gcd(b,a%b):b;
}
int cross(pair<int,int>a,pair<int,int>b){
    return a.first*b.second-a.second*b.first;
}
int dir[4][2]={{-1,0},{0,-1},{1,0},{0,1}};
struct EDGE{
	int v,next,flag;
}edge[MAX];
int tot=0;
int head[MAX];
int stk[MAX];
int top=0;
int d[MAX],h[MAX];
int DN=0;
int CN=0;
int n=0;

int main(){
	int m,i,j;
	int Q;
	int CS=1;
	int n;
	cin>>n;
	vector<int>d;

	for(i=0;i<n;i++){
		d.push_back(0);
		cin>>d[i];
	}

	vector<pair<int,int> >ans;

	m=d[n-1]+1;

	while(d.size()>0){
		for(i=m-d[0]+1;i<=m;i++){
			for(j=i+1;j<=m;j++){
				ans.push_back(make_pair(i,j));
			}

			for(j=1;j<m-d[0]+1;j++){
				ans.push_back(make_pair(i,j));
			}
		}
		m-=d[0];
		if((int)d.size()>1){
			m-=d.back()-d[d.size()-2];
		}
		int tmp=d[0];
		d.erase(d.begin());
		if(d.size()>0){
			d.erase(d.end()-1);
		}
		for(i=0;i<d.size();i++){
			d[i]-=tmp;
		}

	}
	printf("%d\n",(int)ans.size());
	for(i=0;i<ans.size();i++){
		printf("%d %d\n",ans[i].first,ans[i].second);
	}
	return 0;
}


#pragma GCC target("avx2")
#pragma GCC optimize("O3")

# include <x86intrin.h>
# include <bits/stdc++.h>

# include <ext/pb_ds/assoc_container.hpp>
# include <ext/pb_ds/tree_policy.hpp>

using namespace __gnu_pbds;
using namespace std;

template<typename T> using ordered_set = tree <T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;

#define _USE_MATH_DEFINES_
#define ll long long
#define ld long double
#define Accepted 0
#define pb push_back
#define mp make_pair
#define sz(x) (int)(x.size())
#define every(x) x.begin(),x.end()
#define F first
#define S second
#define lb lower_bound
#define ub upper_bound
#define For(i,x,y)  for (ll i = x; i <= y; i ++)
#define FOr(i,x,y)  for (ll i = x; i >= y; i --)
#define SpeedForce ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0)
// ROAD to...                                                                                Red

inline void Input_Output () {
	//freopen(".in", "r", stdin);
   //freopen(".out", "w", stdout);
}

const double eps = 0.000001;
const ld pi = acos(-1);
const int maxn = 1e7 + 9;
const int mod = 1e9 + 7;
const ll MOD = 1e18 + 9;
const ll INF = 1e18 + 123;
const int inf = 2e9 + 11;
const int mxn = 1e6 + 9;
const int N = 3e5 + 123;
const int M = 22;
const int pri = 997;
const int Magic = 2101;

const int dx[] = {-1, 0, 1, 0};
const int dy[] = {0, -1, 0, 1};

int n, m, k;
vector < pair < int, int > > g[N];

int p[N];
int sz[N];

int get (int x) {
	if (p[x] != x) p[x] = get(p[x]);
	return p[x];
}

bool uni (int x, int y) {
	x = get(x);
	y = get(y);

	if (x == y) return 0;
	if (sz[x] > sz[y]) swap(x, y);

	p[x] = y;
	sz[y] += sz[x];

	return 1;
}

inline void init () {
	for (int i = 1; i <= n; i ++) {
		p[i] = i;
		sz[i] = 1;
	}
}
int par[N];

int l[N];
int r[N];
ll d[N];
ll ans[N];
int a[N];
int b[N];

int main () {
   SpeedForce;
   int q;
	cin >> n >> m >> k >> q;

	for (int i = 1; i <= m; i ++) {
		int l, r, x;
		cin >> l >> r >> x;
		g[l].pb({r, x});
		g[r].pb({l, x});
	}
	for (int i = 1; i <= q; i ++) {
		cin >> a[i] >> b[i];
	}

	//cerr << "edges: fin\n";

	for (int i = 1; i <= n; i ++) {
		d[i] = INF;
	}

	priority_queue < pair < ll, int > > qu;
	init();
	for (int i = 1; i <= k; i ++) {
		int x = i;
		qu.push({0, x});
		d[x] = 0;
	}
//	cerr << "special: fin\n";

	while (qu.size()) {
		int v = qu.top().S;
		qu.pop();

		for (auto e : g[v]) if (d[e.F] > d[v] + e.S) {
			d[e.F] = d[v] + e.S;
			p[e.F] = p[v];
			qu.push({d[e.F], e.F});
		}
	}
	vector < pair < ll, pair < int, int > > > edge;

	for (int i = 1; i <= n; i ++) for (auto e : g[i]) {
		int j = e.F;
		if (i < j && p[i] != p[j]) {
			edge.pb({d[i] + d[j] + e.S, {p[i], p[j]}});
		}
	}

	sort(every(edge));
	vector < pair < int, int > > Q, Q2;
	for (int i = 1; i <= q; i ++) {
	//	cin >> a[i] >> b[i];

		l[i] = 0;
		r[i] = edge.size() - 1;
		Q.pb({(l[i] + r[i]) >> 1, i});
		ans[i] = INF;
	}
//	cerr << "query: fin\n";

	while (sz(Q)) {
		sort(every(Q));
		init();

		ll last = 0;
		int ptr = 0;
		for (auto &cur : Q) {
			while (ptr <= cur.F) {
				uni(edge[ptr].S.F, edge[ptr].S.S);
				last = edge[ptr].F;
				ptr++;
			}
			int id = cur.S;
			if (get(a[id]) == get(b[id])) {
				r[id] = cur.F - 1;
				ans[id] = last;
			} else l[id] = cur.F + 1;
			if (l[id] <= r[id])
				Q2.pb({(l[id] + r[id]) >> 1, id});
		}

		swap(Q, Q2);
		Q2.clear();
	}

	for (int i = 1; i <= q; i ++)
		cout << ans[i] << '\n';

   return Accepted;
}

// B...a


#pragma GCC target("avx2")
#pragma GCC optimize("O3")

# include <x86intrin.h>
# include <bits/stdc++.h>

# include <ext/pb_ds/assoc_container.hpp>
# include <ext/pb_ds/tree_policy.hpp>

using namespace __gnu_pbds;
using namespace std;

template<typename T> using ordered_set = tree <T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;

#define _USE_MATH_DEFINES_
#define ll long long
#define ld long double
#define Accepted 0
#define pb push_back
#define mp make_pair
#define sz(x) (int)(x.size())
#define every(x) x.begin(),x.end()
#define F first
#define S second
#define lb lower_bound
#define ub upper_bound
#define For(i,x,y)  for (ll i = x; i <= y; i ++)
#define FOr(i,x,y)  for (ll i = x; i >= y; i --)
#define SpeedForce ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0)
// ROAD to...                                                                                Red

inline void Input_Output () {
	//freopen(".in", "r", stdin);
   //freopen(".out", "w", stdout);
}

const double eps = 0.000001;
const ld pi = acos(-1);
const int maxn = 1e7 + 9;
const int mod = 1e9 + 7;
const ll MOD = 1e18 + 9;
const ll INF = 1e18 + 123;
const int inf = 2e9 + 11;
const int mxn = 1e6 + 9;
const int N = 3e5 + 123;
const int M = 22;
const int pri = 997;
const int Magic = 2101;

const int dx[] = {-1, 0, 1, 0};
const int dy[] = {0, -1, 0, 1};

int n, m, k;
vector < pair < int, int > > g[N];

int p[N];
int sz[N];

int get (int x) {
	if (p[x] != x) p[x] = get(p[x]);
	return p[x];
}

bool uni (int x, int y) {
	x = get(x);
	y = get(y);

	if (x == y) return 0;
	if (sz[x] > sz[y]) swap(x, y);

	p[x] = y;
	sz[y] += sz[x];

	return 1;
}

inline void init () {
	for (int i = 1; i <= n; i ++) {
		p[i] = i;
		sz[i] = 1;
	}
}
int par[N];

int l[N];
int r[N];
ll d[N];
ll ans[N];
int a[N];
int b[N];

int main () {
   SpeedForce;
   int q;
	cin >> n >> m >> k >> q;

	for (int i = 1; i <= m; i ++) {
		int l, r, x;
		cin >> l >> r >> x;
		g[l].pb({r, x});
		g[r].pb({l, x});
	}
	for (int i = 1; i <= q; i ++) {
		cin >> a[i] >> b[i];
	}

	//cerr << "edges: fin\n";

	for (int i = 1; i <= n; i ++) {
		d[i] = INF;
	}

	priority_queue < pair < ll, int > > qu;
	init();
	for (int i = 1; i <= k; i ++) {
		int x = i;
		qu.push({0, x});
		d[x] = 0;
	}
//	cerr << "special: fin\n";

	while (qu.size()) {
		int v = qu.top().S;

		if (qu.top().F != d[v]) {
			qu.pop();
			continue;
		}

		qu.pop();

		for (auto e : g[v]) if (d[e.F] > d[v] + e.S) {
			d[e.F] = d[v] + e.S;
			p[e.F] = p[v];
			qu.push({d[e.F], e.F});
		}
	}
	vector < pair < ll, pair < int, int > > > edge;

	for (int i = 1; i <= n; i ++) for (auto e : g[i]) {
		int j = e.F;
		if (i < j && p[i] != p[j]) {
			edge.pb({d[i] + d[j] + e.S, {p[i], p[j]}});
		}
	}

	sort(every(edge));
	vector < pair < int, int > > Q, Q2;
	for (int i = 1; i <= q; i ++) {
		l[i] = 0;
		r[i] = edge.size() - 1;
		Q.pb({(l[i] + r[i]) >> 1, i});
		ans[i] = INF;
	}

	while (sz(Q)) {
		sort(every(Q));
		init();

		ll last = 0;
		int ptr = 0;
		for (auto &cur : Q) {
			while (ptr <= cur.F) {
				uni(edge[ptr].S.F, edge[ptr].S.S);
				last = edge[ptr].F;
				ptr++;
			}
			int id = cur.S;
			if (get(a[id]) == get(b[id])) {
				r[id] = cur.F - 1;
				ans[id] = last;
			} else l[id] = cur.F + 1;
			if (l[id] <= r[id])
				Q2.pb({(l[id] + r[id]) >> 1, id});
		}

		swap(Q, Q2);
		Q2.clear();
	}

	for (int i = 1; i <= q; i ++)
		cout << ans[i] << '\n';

   return Accepted;
}

// B...a


#include <bits/stdc++.h>
#pragma GCC optimize "03"
#define ll long long
using namespace std;
#define fastio ios_base::sync_with_stdio(0);cin.tie(NULL);
#define pii pair<ll , ll>
#define mpi make_pair
#define F first
#define S second
#define pb push_back
#define For(i,j,k) for (int i=(int)(j);i<=(int)(k);i++)
#define Rep(i,j,k) for (int i=(int)(j);i>=(int)(k);i--)
#define endl '\n'
#define vii vector<ll>
#define INF 1e18

vector<vector<pii>> ng;
ll dist[100005];
vector<int> par;
vector<set<int>> qnow;
vector<ll> ans;

int find(int u){
    if(par[u] == u)return u;
    else return par[u] = find(par[u]);
}

void join(int u , int v , ll w){

    int a = find(u);
    int b = find(v);

    if(a == b)return;

    if(qnow[a].size() > qnow[b].size()){
        par[b] = a;

        for(auto x:qnow[b]){
            if(qnow[a].find(x) != qnow[a].end()){
                qnow[a].erase(x);
                ans[x] = w;
            }
            else qnow[a].insert(x);
        }
    }

    else{
        par[a] = b;

        for(auto x:qnow[a]){
            if(qnow[b].find(x) != qnow[b].end()){
                qnow[b].erase(x);
                ans[x] = w;
            }
            else qnow[b].insert(x);
        }

    }
}
int main()
{
    fastio;
    int n ,m , k , q;

    cin>>n>>m>>k>>q;

    ng.resize(n+1);
    par.resize(n+1);
    qnow.resize(n+1);
    ans.resize(q , -1);

    vector<pair<ll , pii>> edg(m);
    For(i , 0 , m-1){
        int u , v , w;
        cin>>u>>v>>w;
        ng[u].pb(mpi(v, w));
        ng[v].pb(mpi(u ,w));
        edg[i] = mpi(w , mpi(u , v));
    }

    For(i , k+1, n)dist[i] = INT_MAX;

    vector<bool> vis(n+1, false);

    set<pair<ll , pii>> se;

    For(i , 1 , k)se.insert(mpi(0 , mpi(i , i)));

    while(!se.empty()){
        pair<ll , pii> tp = *(se.begin());
        se.erase(se.begin());

        if(vis[tp.S.F])continue;

        dist[tp.S.F] = tp.F;
        vis[tp.S.F] = true;
        par[tp.S.F] = tp.S.S;

        for(auto x:ng[tp.S.F]){
            if(!vis[x.F])se.insert(mpi((ll)tp.F+x.S , mpi(x.F , par[tp.S.F])));
        }
    }

    // For(i , 1 , n)cout<<dist[i]<<" ";cout<<endl;
    // For(i , 1 , n)cout<<par[i]<<" ";cout<<endl;

    For(i , 0 , m-1){
        if(par[edg[i].S.F] != par[edg[i].S.S]) edg[i].F = (ll)edg[i].F + dist[edg[i].S.F] + dist[edg[i].S.S];
    }

    sort(edg.begin() , edg.end());

    // for(auto x:edg){
    //     cout<<x.F<<" "<<x.S.F<<" "<<x.S.S<<endl;
    // }

    vector<pii> qer(q);

    For(i , 0 , q-1){
        int u ,v;
        cin>>u>>v;
        qer[i] = mpi(u , v);
        qnow[u].insert(i);
        qnow[v].insert(i);
    }

    For(i , 0 , m-1){
        ll u , v , w;
        u = edg[i].S.F;
        v = edg[i].S.S;
        w = edg[i].F;
        // cout<<u<<" "<<v<<" "<<w<<endl;
        join(u , v , w);
    }

    For(i , 0 , q-1)cout<<ans[i]<<endl;

    return 0;
}


#include <bits/stdc++.h>
#define ll long long
using namespace std;
#define fastio ios_base::sync_with_stdio(0);cin.tie(NULL);
#define pii pair<ll , ll>
#define mpi make_pair
#define F first
#define S second
#define pb push_back
#define For(i,j,k) for (int i=(int)(j);i<=(int)(k);i++)
#define Rep(i,j,k) for (int i=(int)(j);i>=(int)(k);i--)
#define endl '\n'
#define vii vector<ll>
#define INF 1e18

vector<vector<pii>> ng;
ll dist[100005];
vector<int> par;
vector<set<int>> qnow;
vector<ll> ans;

int find(int u){
    if(par[u] == u)return u;
    else return par[u] = find(par[u]);
}

void join(int u , int v , ll w){

    int a = find(u);
    int b = find(v);

    if(a == b)return;

    if(qnow[a].size() > qnow[b].size()){
        par[b] = a;

        for(auto x:qnow[b]){
            if(qnow[a].find(x) != qnow[a].end()){
                qnow[a].erase(x);
                ans[x] = w;
            }
            else qnow[a].insert(x);
        }
    }

    else{
        par[a] = b;

        for(auto x:qnow[a]){
            if(qnow[b].find(x) != qnow[b].end()){
                qnow[b].erase(x);
                ans[x] = w;
            }
            else qnow[b].insert(x);
        }

    }
}
int main()
{
    fastio;
    int n ,m , k , q;

    cin>>n>>m>>k>>q;

    ng.resize(n+1);
    par.resize(n+1);
    qnow.resize(n+1);
    ans.resize(q , -1);

    vector<pair<ll , pii>> edg(m);
    For(i , 0 , m-1){
        int u , v , w;
        cin>>u>>v>>w;
        ng[u].pb(mpi(v, w));
        ng[v].pb(mpi(u ,w));
        edg[i] = mpi(w , mpi(u , v));
    }

    For(i , k+1, n)dist[i] = INT_MAX;

    vector<bool> vis(n+1, false);

    set<pair<ll , pii>> se;

    For(i , 1 , k)se.insert(mpi(0 , mpi(i , i)));

    while(!se.empty()){
        pair<ll , pii> tp = *(se.begin());
        se.erase(se.begin());

        if(vis[tp.S.F])continue;

        dist[tp.S.F] = tp.F;
        vis[tp.S.F] = true;
        par[tp.S.F] = tp.S.S;

        for(auto x:ng[tp.S.F]){
            if(!vis[x.F])se.insert(mpi((ll)tp.F+x.S , mpi(x.F , par[tp.S.F])));
        }
    }

    // For(i , 1 , n)cout<<dist[i]<<" ";cout<<endl;
    // For(i , 1 , n)cout<<par[i]<<" ";cout<<endl;

    For(i , 0 , m-1){
        if(par[edg[i].S.F] != par[edg[i].S.S]) edg[i].F = (ll)edg[i].F + dist[edg[i].S.F] + dist[edg[i].S.S];
    }

    sort(edg.begin() , edg.end());

    // for(auto x:edg){
    //     cout<<x.F<<" "<<x.S.F<<" "<<x.S.S<<endl;
    // }

    vector<pii> qer(q);

    For(i , 0 , q-1){
        int u ,v;
        cin>>u>>v;
        qer[i] = mpi(u , v);
        qnow[u].insert(i);
        qnow[v].insert(i);
    }

    For(i , 0 , m-1){
        ll u , v , w;
        u = edg[i].S.F;
        v = edg[i].S.S;
        w = edg[i].F;
        // cout<<u<<" "<<v<<" "<<w<<endl;
        join(u , v , w);
    }

    For(i , 0 , q-1)cout<<ans[i]<<endl;

    return 0;
}


#include <bits/stdc++.h>
#define ll long long
using namespace std;
#define fastio ios_base::sync_with_stdio(0);cin.tie(NULL);
#define pii pair<ll , ll>
#define mpi make_pair
#define F first
#define S second
#define pb push_back
#define For(i,j,k) for (int i=(int)(j);i<=(int)(k);i++)
#define Rep(i,j,k) for (int i=(int)(j);i>=(int)(k);i--)
#define endl '\n'
#define vii vector<ll>
#define INF 1e18

vector<vector<pii>> ng;
int dist[100005];
vector<int> par;
vector<set<int>> qnow;
vector<int> ans;

int find(int u){
    if(par[u] == u)return u;
    else return par[u] = find(par[u]);
}

void join(int u , int v , int w){

    int a = find(u);
    int b = find(v);

    if(a == b)return;

    if(qnow[a].size() > qnow[b].size()){
        par[b] = a;

        for(auto x:qnow[b]){
            if(qnow[a].find(x) != qnow[a].end()){
                qnow[a].erase(x);
                ans[x] = w;
            }
            else qnow[a].insert(x);
        }
    }

    else{
        par[a] = b;

        for(auto x:qnow[a]){
            if(qnow[b].find(x) != qnow[b].end()){
                qnow[b].erase(x);
                ans[x] = w;
            }
            else qnow[b].insert(x);
        }

    }
}
int main()
{
    fastio;
    int n ,m , k , q;

    cin>>n>>m>>k>>q;

    ng.resize(n+1);
    par.resize(n+1);
    qnow.resize(n+1);
    ans.resize(q , -1);

    vector<pair<int , pii>> edg(m);
    For(i , 0 , m-1){
        int u , v , w;
        cin>>u>>v>>w;
        ng[u].pb(mpi(v, w));
        ng[v].pb(mpi(u ,w));
        edg[i] = mpi(w , mpi(u , v));
    }

    For(i , k+1, n)dist[i] = INT_MAX;

    vector<bool> vis(n+1, false);

    set<pair<int , pii>> se;

    For(i , 1 , k)se.insert(mpi(0 , mpi(i , i)));

    while(!se.empty()){
        pair<int , pii> tp = *(se.begin());
        se.erase(se.begin());

        if(vis[tp.S.F])continue;

        dist[tp.S.F] = tp.F;
        vis[tp.S.F] = true;
        par[tp.S.F] = tp.S.S;

        for(auto x:ng[tp.S.F]){
            if(!vis[x.F])se.insert(mpi(tp.F+x.S , mpi(x.F , par[tp.S.F])));
        }
    }

    // For(i , 1 , n)cout<<dist[i]<<" ";cout<<endl;
    // For(i , 1 , n)cout<<par[i]<<" ";cout<<endl;

    For(i , 0 , m-1){
        if(par[edg[i].S.F] != par[edg[i].S.S]) edg[i].F = edg[i].F + dist[edg[i].S.F] + dist[edg[i].S.S];
    }

    sort(edg.begin() , edg.end());

    // for(auto x:edg){
    //     cout<<x.F<<" "<<x.S.F<<" "<<x.S.S<<endl;
    // }
    map<pii , int> ump;

    vector<pii> qer(q);

    For(i , 0 , q-1){
        int u ,v;
        cin>>u>>v;
        qer[i] = mpi(u , v);
        qnow[u].insert(i);
        qnow[v].insert(i);
    }

    For(i , 0 , m-1){
        int u , v , w;
        u = edg[i].S.F;
        v = edg[i].S.S;
        w = edg[i].F;
        // cout<<u<<" "<<v<<" "<<w<<endl;
        join(u , v , w);
    }

    For(i , 0 , q-1)cout<<ans[i]<<endl;

    return 0;
}


#include <bits/stdc++.h>
#define ll long long
using namespace std;
#define fastio ios_base::sync_with_stdio(0);cin.tie(NULL);
#define pii pair<ll , ll>
#define mpi make_pair
#define F first
#define S second
#define pb push_back
#define For(i,j,k) for (int i=(int)(j);i<=(int)(k);i++)
#define Rep(i,j,k) for (int i=(int)(j);i>=(int)(k);i--)
#define endl '\n'
#define vii vector<ll>
#define INF 1e18

vector<vector<pii>> ng;
ll dist[100005];
vector<int> par;
vector<set<int>> qnow;
vector<ll> ans;

int find(int u){
    if(par[u] == u)return u;
    else return par[u] = find(par[u]);
}

void join(int u , int v , ll w){

    int a = find(u);
    int b = find(v);

    if(a == b)return;

    // if(qnow[a].size() > qnow[b].size()){
        par[b] = a;

        for(auto x:qnow[b]){
            if(qnow[a].find(x) != qnow[a].end()){
                qnow[a].erase(x);
                ans[x] = w;
            }
            else qnow[a].insert(x);
        }
    // }

    // else{
    //     par[a] = b;

    //     for(auto x:qnow[a]){
    //         if(qnow[b].find(x) != qnow[b].end()){
    //             qnow[b].erase(x);
    //             ans[x] = w;
    //         }
    //         else qnow[b].insert(x);
    //     }

    // }
}
int main()
{
    fastio;
    int n ,m , k , q;

    cin>>n>>m>>k>>q;

    ng.resize(n+1);
    par.resize(n+1);
    qnow.resize(n+1);
    ans.resize(q , -1);

    vector<pair<ll , pii>> edg(m);
    For(i , 0 , m-1){
        int u , v , w;
        cin>>u>>v>>w;
        ng[u].pb(mpi(v, w));
        ng[v].pb(mpi(u ,w));
        edg[i] = mpi(w , mpi(u , v));
    }

    For(i , k+1, n)dist[i] = INT_MAX;

    vector<bool> vis(n+1, false);

    set<pair<ll , pii>> se;

    For(i , 1 , k)se.insert(mpi(0 , mpi(i , i)));

    while(!se.empty()){
        pair<ll , pii> tp = *(se.begin());
        se.erase(se.begin());

        if(vis[tp.S.F])continue;

        dist[tp.S.F] = tp.F;
        vis[tp.S.F] = true;
        par[tp.S.F] = tp.S.S;

        for(auto x:ng[tp.S.F]){
            if(!vis[x.F])se.insert(mpi((ll)tp.F+x.S , mpi(x.F , par[tp.S.F])));
        }
    }

    // For(i , 1 , n)cout<<dist[i]<<" ";cout<<endl;
    // For(i , 1 , n)cout<<par[i]<<" ";cout<<endl;

    For(i , 0 , m-1){
        if(par[edg[i].S.F] != par[edg[i].S.S]) edg[i].F = (ll)edg[i].F + dist[edg[i].S.F] + dist[edg[i].S.S];
    }

    sort(edg.begin() , edg.end());

    // for(auto x:edg){
    //     cout<<x.F<<" "<<x.S.F<<" "<<x.S.S<<endl;
    // }

    vector<pii> qer(q);

    For(i , 0 , q-1){
        int u ,v;
        cin>>u>>v;
        qer[i] = mpi(u , v);
        qnow[u].insert(i);
        qnow[v].insert(i);
    }

    For(i , 0 , m-1){
        ll u , v , w;
        u = edg[i].S.F;
        v = edg[i].S.S;
        w = edg[i].F;
        // cout<<u<<" "<<v<<" "<<w<<endl;
        join(u , v , w);
    }

    For(i , 0 , q-1)cout<<ans[i]<<endl;

    return 0;
}


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

const Long MX = 1e5 + 10;
const Long INF = 1e17;
const Long K = 20;

vector< pair<Long,pair<Long,Long> > > aristas;
vector<Long> o_adj[MX];
vector<Long> o_pes[MX];
vector<Long> adj[MX];
vector<Long> pes[MX];

Long dist[MX];
Long root[MX];
Long parent[MX];
Long rnk[MX];

Long findSet(Long i){
	if(parent[i]==i) return i;
	parent[i]=findSet(parent[i]);
	return parent[i];
}

void unionSet(Long i, Long j){
	Long x=findSet(i);
	Long y=findSet(j);
	if(y!=x){
		if(rnk[x]>rnk[y]){
			parent[y]=x;
		}else{
			parent[x]=y;
			if(rnk[x]==rnk[y]){
				rnk[y]++;
			}
		}
	}
	return;
}

Long F[K][MX];
Long C[K][MX];
Long D[MX];

void lca_dfs(Long u){
	Long sz = adj[u].size();
	for(Long i = 0; i < sz; i++){
		Long v = adj[u][i];
		if(v == F[0][u]) continue;
		F[0][v] = u;
		C[0][v] = pes[u][i];
		D[v] = D[u] + 1;
		lca_dfs(v);
	}
	return;
}

void lca_init(Long x, Long n){
	D[x] = 0;
	F[0][x] = -1;
	C[0][x] = 0;
	lca_dfs(x);
	for(Long k = 1; k < K; k++){
		for(Long x = 0; x < n; x++){
			if(F[k-1][x] < 0){
				F[k][x] = -1;
			}else{
				F[k][x] = F[k-1][F[k-1][x]];
				C[k][x] = max(C[k-1][x],C[k-1][F[k-1][x]]);
			}
		}
	}
	return;
}

Long lca(Long x, Long y){
	Long ans = 0;
	if(D[x] < D[y]) swap(x,y);
	for(Long k = K-1; k >= 0; k--){
		if(D[x] - (1ll<<k) >= D[y]){
			ans = max(ans,C[k][x]);
			x = F[k][x];
		}
	}
	if(x == y) return ans;
	for(Long k = K-1; k >= 0; k--){
		if(F[k][x] != F[k][y]){
			ans = max(ans,C[k][x]);
			ans = max(ans,C[k][y]);
			x = F[k][x];
			y = F[k][y];
		}
	}
	return max({ans,C[0][x],C[0][y]});
}

int main(){
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);
	cout.precision(10);
	cout << fixed;

	for(Long i = 0; i < MX; i++) parent[i] = i;

	Long n, m, k, q, x, y, w;
	cin >> n >> m >> k >> q;

	for(Long i = 0; i < m; i++){
		cin >> x >> y >> w;
		o_adj[x].push_back(y);
		o_pes[x].push_back(w);
		o_adj[y].push_back(x);
		o_pes[y].push_back(w);
	}

	priority_queue< pair<Long,Long> > pq;
	for(Long i = 0; i <= n; i++) dist[i] = root[i] = INF;
	for(Long i = 1; i <= k; i++){
		dist[i] = 0;
		root[i] = i;
		pq.push({0ll,i});
	}

	while(!pq.empty()){
		Long d = -pq.top().first;
		Long u = pq.top().second;
		pq.pop();

		if(dist[u] != d) continue;

		Long sz = o_adj[u].size();
		for(Long i = 0; i < sz; i++){
			Long v = o_adj[u][i];
			Long ww = o_pes[u][i];
			if(dist[v] > d + ww){
				dist[v] = d + ww;
				root[v] = root[u];
				pq.push({-dist[v],v});
			}else{
				if(root[u] <= k && root[v] <= k && root[u] != root[v]){
					Long aux = ww + dist[v] + dist[u];
					aristas.push_back({aux,{root[u],root[v]}});
				}
			}
		}
	}

	sort(aristas.begin(),aristas.end());
	for(Long i = 0; i < aristas.size(); i++){
		w = aristas[i].first;
		x = aristas[i].second.first;
		y = aristas[i].second.second;
		if(findSet(x) != findSet(y)){
			adj[x].push_back(y);
			pes[x].push_back(w);
			adj[y].push_back(x);
			pes[y].push_back(w);
			unionSet(x,y);
		}
	}

	lca_init(1,k+1);

	for(Long i = 0; i < q; i++){
		cin >> x >> y;
		cout << lca(x,y) << "\n";
	}
	return 0;
}


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

const Long MX = 1e5 + 10;
const Long K = 20;

vector<Long> o_adj[MX];
vector<Long> o_pes[MX];
vector<Long> adj[MX];
vector<Long> pes[MX];

map<Long,Long> dist[MX];

Long parent[MX];
Long rnk[MX];

Long findSet(Long i){
	if(parent[i]==i){
		return i;
	}
	parent[i]=findSet(parent[i]);
	return parent[i];
}

void unionSet(Long i, Long j){
	Long x=findSet(i);
	Long y=findSet(j);
	if(y!=x){
		if(rnk[x]>rnk[y]){
			parent[y]=x;
		}else{
			parent[x]=y;
			if(rnk[x]==rnk[y]){
				rnk[y]++;
			}
		}
	}
	return;
}

Long F[K][MX];
Long C[K][MX];
Long D[MX];

void lca_dfs(Long u){
	Long sz = adj[u].size();
	for(Long i = 0; i < sz; i++){
		Long v = adj[u][i];
		if(v == F[0][u]) continue;
		F[0][v] = u;
		C[0][v] = pes[u][i];
		D[v] = D[u] + 1;
		lca_dfs(v);
	}
	return;
}

void lca_init(Long x, Long n){
	D[x] = 0;
	F[0][x] = -1;
	C[0][x] = 0;
	lca_dfs(x);
	for(Long k = 1; k < K; k++){
		for(Long x = 0; x < n; x++){
			if(F[k-1][x] < 0){
				F[k][x] = -1;
			}else{
				F[k][x] = F[k-1][F[k-1][x]];
				C[k][x] = max(C[k-1][x],C[k-1][F[k-1][x]]);
			}
		}
	}
	return;
}

Long lca(Long x, Long y){
	Long ans = 0;
	if(D[x] < D[y]) swap(x,y);
	for(Long k = K-1; k >= 0; k--){
		if(D[x] - (1ll<<k) >= D[y]){
			ans = max(ans,C[k][x]);
			x = F[k][x];
		}
	}
	if(x == y) return ans;
	for(Long k = K-1; k >= 0; k--){
		if(F[k][x] != F[k][y]){
			ans = max(ans,C[k][x]);
			ans = max(ans,C[k][y]);
			x = F[k][x];
			y = F[k][y];
		}
	}
	return max({ans,C[0][x],C[0][y]});
}

int main(){
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);
	cout.precision(10);
	cout << fixed;

	for(Long i = 0; i < MX; i++) parent[i] = i;

	Long n, m, k, q, x, y, w;
	cin >> n >> m >> k >> q;

	for(Long i = 0; i < m; i++){
		cin >> x >> y >> w;
		o_adj[x].push_back(y);
		o_pes[x].push_back(w);
		o_adj[y].push_back(x);
		o_pes[y].push_back(w);
	}

	priority_queue< pair<Long, pair<Long,Long> > > pq;
	for(Long i = 1; i <= k; i++){
		dist[i][i] = 0;
		pq.push({0ll,{i,i}});
	}

	while(!pq.empty()){
		Long d = -pq.top().first;
		Long u = pq.top().second.first;
		Long v = pq.top().second.second;
		pq.pop();

		if(dist[u][v] != d) continue;

		Long gu = findSet(u);
		Long gv = findSet(v);

		if(u != v && gu == gv) continue;

		if(u <= k && v <= k && gu != gv){
			adj[gu].push_back(gv);
			pes[gu].push_back(d);
			adj[gv].push_back(gu);
			pes[gv].push_back(d);
			unionSet(gu,gv);
		}else{
			u = findSet(u);
			Long sz = o_adj[v].size();
			for(Long i = 0; i < sz; i++){
				Long nv = o_adj[v][i];
				Long ww = o_pes[v][i];
				if(dist[u].find(nv) == dist[u].end() || dist[u][nv] > d + ww){
					dist[u][nv] = d + ww;
					pq.push({-dist[u][nv],{u,nv}});
				}
			}
		}
	}

	lca_init(1,k+1);

	for(Long i = 0; i < q; i++){
		cin >> x >> y;
		cout << lca(x,y) << "\n";
	}
	return 0;
}


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

const Long MX = 1e5 + 10;
const Long K = 20;

vector< pair<Long,pair<Long,Long> > > aristas;
vector<Long> o_adj[MX];
vector<Long> o_pes[MX];
vector<Long> adj[MX];
vector<Long> pes[MX];

Long dist[MX];
Long root[MX];
Long parent[MX];
Long rnk[MX];

Long findSet(Long i){
	if(parent[i]==i) return i;
	parent[i]=findSet(parent[i]);
	return parent[i];
}

void unionSet(Long i, Long j){
	Long x=findSet(i);
	Long y=findSet(j);
	if(y!=x){
		if(rnk[x]>rnk[y]){
			parent[y]=x;
		}else{
			parent[x]=y;
			if(rnk[x]==rnk[y]){
				rnk[y]++;
			}
		}
	}
	return;
}

Long F[K][MX];
Long C[K][MX];
Long D[MX];

void lca_dfs(Long u){
	Long sz = adj[u].size();
	for(Long i = 0; i < sz; i++){
		Long v = adj[u][i];
		if(v == F[0][u]) continue;
		F[0][v] = u;
		C[0][v] = pes[u][i];
		D[v] = D[u] + 1;
		lca_dfs(v);
	}
	return;
}

void lca_init(Long x, Long n){
	D[x] = 0;
	F[0][x] = -1;
	C[0][x] = 0;
	lca_dfs(x);
	for(Long k = 1; k < K; k++){
		for(Long x = 0; x < n; x++){
			if(F[k-1][x] < 0){
				F[k][x] = -1;
			}else{
				F[k][x] = F[k-1][F[k-1][x]];
				C[k][x] = max(C[k-1][x],C[k-1][F[k-1][x]]);
			}
		}
	}
	return;
}

Long lca(Long x, Long y){
	Long ans = 0;
	if(D[x] < D[y]) swap(x,y);
	for(Long k = K-1; k >= 0; k--){
		if(D[x] - (1ll<<k) >= D[y]){
			ans = max(ans,C[k][x]);
			x = F[k][x];
		}
	}
	if(x == y) return ans;
	for(Long k = K-1; k >= 0; k--){
		if(F[k][x] != F[k][y]){
			ans = max(ans,C[k][x]);
			ans = max(ans,C[k][y]);
			x = F[k][x];
			y = F[k][y];
		}
	}
	return max({ans,C[0][x],C[0][y]});
}

int main(){
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);
	cout.precision(10);
	cout << fixed;

	for(Long i = 0; i < MX; i++) parent[i] = i;

	Long n, m, k, q, x, y, w;
	cin >> n >> m >> k >> q;

	for(Long i = 0; i < m; i++){
		cin >> x >> y >> w;
		o_adj[x].push_back(y);
		o_pes[x].push_back(w);
		o_adj[y].push_back(x);
		o_pes[y].push_back(w);
	}

	priority_queue< pair<Long,Long> > pq;
	for(Long i = 0; i <= n; i++) dist[i] = root[i] = MX;
	for(Long i = 1; i <= k; i++){
		dist[i] = 0;
		root[i] = i;
		pq.push({0ll,i});
	}

	while(!pq.empty()){
		Long d = -pq.top().first;
		Long u = pq.top().second;
		pq.pop();

		if(dist[u] != d) continue;

		Long sz = o_adj[u].size();
		for(Long i = 0; i < sz; i++){
			Long v = o_adj[u][i];
			Long ww = o_pes[u][i];
			if(dist[v] > d + ww){
				dist[v] = d + ww;
				root[v] = root[u];
				pq.push({-dist[v],v});
			}else{
				if(root[u] <= k && root[v] <= k && root[u] != root[v]){
					Long aux = ww + dist[v] + dist[u];
					aristas.push_back({aux,{root[u],root[v]}});
				}
			}
		}
	}

	sort(aristas.begin(),aristas.end());
	for(Long i = 0; i < aristas.size(); i++){
		w = aristas[i].first;
		x = aristas[i].second.first;
		y = aristas[i].second.second;
		if(findSet(x) != findSet(y)){
			adj[x].push_back(y);
			pes[x].push_back(w);
			adj[y].push_back(x);
			pes[y].push_back(w);
			unionSet(x,y);
		}
	}

	lca_init(1,k+1);

	for(Long i = 0; i < q; i++){
		cin >> x >> y;
		cout << lca(x,y) << "\n";
	}
	return 0;
}


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

const Long MX = 1e5 + 10;
const Long K = 20;

vector<Long> o_adj[MX];
vector<Long> o_pes[MX];
vector<Long> adj[MX];
vector<Long> pes[MX];

map<Long,Long> dist[MX];

Long parent[MX];
Long rnk[MX];

Long findSet(Long i){
	if(parent[i]==i){
		return i;
	}
	parent[i]=findSet(parent[i]);
	return parent[i];
}

void unionSet(Long i, Long j){
	Long x=findSet(i);
	Long y=findSet(j);
	if(y!=x){
		if(rnk[x]>rnk[y]){
			parent[y]=x;
		}else{
			parent[x]=y;
			if(rnk[x]==rnk[y]){
				rnk[y]++;
			}
		}
	}
	return;
}

Long F[K][MX];
Long C[K][MX];
Long D[MX];

void lca_dfs(Long u){
	Long sz = adj[u].size();
	for(Long i = 0; i < sz; i++){
		Long v = adj[u][i];
		if(v == F[0][u]) continue;
		F[0][v] = u;
		C[0][v] = pes[u][i];
		D[v] = D[u] + 1;
		lca_dfs(v);
	}
	return;
}

void lca_init(Long x, Long n){
	D[x] = 0;
	F[0][x] = -1;
	C[0][x] = 0;
	lca_dfs(x);
	for(Long k = 1; k < K; k++){
		for(Long x = 0; x < n; x++){
			if(F[k-1][x] < 0){
				F[k][x] = -1;
			}else{
				F[k][x] = F[k-1][F[k-1][x]];
				C[k][x] = max(C[k-1][x],C[k-1][F[k-1][x]]);
			}
		}
	}
	return;
}

Long lca(Long x, Long y){
	Long ans = 0;
	if(D[x] < D[y]) swap(x,y);
	for(Long k = K-1; k >= 0; k--){
		if(D[x] - (1ll<<k) >= D[y]){
			ans = max(ans,C[k][x]);
			x = F[k][x];
		}
	}
	if(x == y) return ans;
	for(Long k = K-1; k >= 0; k--){
		if(F[k][x] != F[k][y]){
			ans = max(ans,C[k][x]);
			ans = max(ans,C[k][y]);
			x = F[k][x];
			y = F[k][y];
		}
	}
	return max({ans,C[0][x],C[0][y]});
}

int main(){
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);
	cout.precision(10);
	cout << fixed;

	for(Long i = 0; i < MX; i++) parent[i] = i;

	Long n, m, k, q, x, y, w;
	cin >> n >> m >> k >> q;

	for(Long i = 0; i < m; i++){
		cin >> x >> y >> w;
		o_adj[x].push_back(y);
		o_pes[x].push_back(w);
		o_adj[y].push_back(x);
		o_pes[y].push_back(w);
	}

	priority_queue< pair<Long, pair<Long,Long> > > pq;
	for(Long i = 1; i <= k; i++){
		dist[i][i] = 0;
		pq.push({0ll,{i,i}});
	}

	while(!pq.empty()){
		Long d = -pq.top().first;
		Long u = pq.top().second.first;
		Long v = pq.top().second.second;
		pq.pop();

		if(dist[u][v] != d) continue;

		Long gu = findSet(u);
		Long gv = findSet(v);

		if((u != v && gu == gv) || gu != u) continue;

		if(u <= k && v <= k && gu != gv){
			adj[gu].push_back(gv);
			pes[gu].push_back(d);
			adj[gv].push_back(gu);
			pes[gv].push_back(d);
			unionSet(gu,gv);
		}else{
			u = findSet(u);
			Long sz = o_adj[v].size();
			for(Long i = 0; i < sz; i++){
				Long nv = o_adj[v][i];
				Long ww = o_pes[v][i];
				if(dist[u].find(nv) == dist[u].end() || dist[u][nv] > d + ww){
					dist[u][nv] = d + ww;
					pq.push({-dist[u][nv],{u,nv}});
				}
			}
		}
	}

	lca_init(1,k+1);

	for(Long i = 0; i < q; i++){
		cin >> x >> y;
		cout << lca(x,y) << "\n";
	}
	return 0;
}


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

const Long MX = 1e5 + 10;
const Long K = 20;

vector<Long> o_adj[MX];
vector<Long> o_pes[MX];
vector<Long> adj[MX];
vector<Long> pes[MX];

map<Long,Long> dist[MX];

Long grupo[MX];
Long parent[MX];
Long rnk[MX];

Long findSet(Long i){
	if(parent[i]==i){
		return i;
	}
	parent[i]=findSet(parent[i]);
	return parent[i];
}

void unionSet(Long i, Long j){
	Long x=findSet(i);
	Long y=findSet(j);
	if(y!=x){
		if(rnk[x]>rnk[y]){
			parent[y]=x;
		}else{
			parent[x]=y;
			if(rnk[x]==rnk[y]){
				rnk[y]++;
			}
		}
	}
	return;
}

Long F[K][MX];
Long C[K][MX];
Long D[MX];

void lca_dfs(Long u){
	Long sz = adj[u].size();
	for(Long i = 0; i < sz; i++){
		Long v = adj[u][i];
		if(v == F[0][u]) continue;
		F[0][v] = u;
		C[0][v] = pes[u][i];
		D[v] = D[u] + 1;
		lca_dfs(v);
	}
	return;
}

void lca_init(Long x, Long n){
	D[x] = 0;
	F[0][x] = -1;
	C[0][x] = 0;
	lca_dfs(x);
	for(Long k = 1; k < K; k++){
		for(Long x = 0; x < n; x++){
			if(F[k-1][x] < 0){
				F[k][x] = -1;
			}else{
				F[k][x] = F[k-1][F[k-1][x]];
				C[k][x] = max(C[k-1][x],C[k-1][F[k-1][x]]);
			}
		}
	}
	return;
}

Long lca(Long x, Long y){
	Long ans = 0;
	if(D[x] < D[y]) swap(x,y);
	for(Long k = K-1; k >= 0; k--){
		if(D[x] - (1ll<<k) >= D[y]){
			ans = max(ans,C[k][x]);
			x = F[k][x];
		}
	}
	if(x == y) return ans;
	for(Long k = K-1; k >= 0; k--){
		if(F[k][x] != F[k][y]){
			ans = max(ans,C[k][x]);
			ans = max(ans,C[k][y]);
			x = F[k][x];
			y = F[k][y];
		}
	}
	return max({ans,C[0][x],C[0][y]});
}

int main(){
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);
	cout.precision(10);
	cout << fixed;

	for(Long i = 0; i < MX; i++) grupo[i] = parent[i] = i;

	Long n, m, k, q, x, y, w;
	cin >> n >> m >> k >> q;

	for(Long i = 0; i < m; i++){
		cin >> x >> y >> w;
		o_adj[x].push_back(y);
		o_pes[x].push_back(w);
		o_adj[y].push_back(x);
		o_pes[y].push_back(w);
	}

	priority_queue< pair<Long, pair<Long,Long> > > pq;
	for(Long i = 1; i <= k; i++){
		dist[i][i] = 0;
		pq.push({0ll,{i,i}});
	}

	while(!pq.empty()){
		Long d = -pq.top().first;
		Long u = pq.top().second.first;
		Long v = pq.top().second.second;
		pq.pop();

		if(dist[u][v] != d) continue;

		Long gu = grupo[u];
		Long gv = grupo[v];

		if(gv > k){
			grupo[v] = gu;
			gv = gu;
		}else{
			if(findSet(gu) != findSet(gv)){
				adj[gu].push_back(gv);
				pes[gu].push_back(d + dist[gv][v]);
				adj[gv].push_back(gu);
				pes[gv].push_back(d + dist[gv][v]);
				unionSet(gu,gv);
			}
		}

		if(gv != gu) continue;
		Long sz = o_adj[v].size();
		for(Long i = 0; i < sz; i++){
			Long nv = o_adj[v][i];
			Long ww = o_pes[v][i];
			if(dist[u].find(nv) == dist[u].end() || dist[u][nv] > d + ww){
				dist[u][nv] = d + ww;
				pq.push({-dist[u][nv],{u,nv}});
			}
		}
	}

	lca_init(1,k+1);

	for(Long i = 0; i < q; i++){
		cin >> x >> y;
		cout << lca(x,y) << "\n";
	}
	return 0;
}


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

const Long MX = 1e5 + 10;
const Long K = 20;

vector<Long> o_adj[MX];
vector<Long> o_pes[MX];
vector<Long> adj[MX];
vector<Long> pes[MX];

map<Long,Long> dist[MX];

Long grupo[MX];
Long parent[MX];
Long rnk[MX];

Long findSet(Long i){
	if(parent[i]==i){
		return i;
	}
	parent[i]=findSet(parent[i]);
	return parent[i];
}

void unionSet(Long i, Long j){
	Long x=findSet(i);
	Long y=findSet(j);
	if(y!=x){
		if(rnk[x]>rnk[y]){
			parent[y]=x;
		}else{
			parent[x]=y;
			if(rnk[x]==rnk[y]){
				rnk[y]++;
			}
		}
	}
	return;
}

Long F[K][MX];
Long C[K][MX];
Long D[MX];

void lca_dfs(Long u){
	Long sz = adj[u].size();
	for(Long i = 0; i < sz; i++){
		Long v = adj[u][i];
		if(v == F[0][u]) continue;
		F[0][v] = u;
		C[0][v] = pes[u][i];
		D[v] = D[u] + 1;
		lca_dfs(v);
	}
	return;
}

void lca_init(Long x, Long n){
	D[x] = 0;
	F[0][x] = -1;
	C[0][x] = 0;
	lca_dfs(x);
	for(Long k = 1; k < K; k++){
		for(Long x = 0; x < n; x++){
			if(F[k-1][x] < 0){
				F[k][x] = -1;
			}else{
				F[k][x] = F[k-1][F[k-1][x]];
				C[k][x] = max(C[k-1][x],C[k-1][F[k-1][x]]);
			}
		}
	}
	return;
}

Long lca(Long x, Long y){
	Long ans = 0;
	if(D[x] < D[y]) swap(x,y);
	for(Long k = K-1; k >= 0; k--){
		if(D[x] - (1ll<<k) >= D[y]){
			ans = max(ans,C[k][x]);
			x = F[k][x];
		}
	}
	if(x == y) return ans;
	for(Long k = K-1; k >= 0; k--){
		if(F[k][x] != F[k][y]){
			ans = max(ans,C[k][x]);
			ans = max(ans,C[k][y]);
			x = F[k][x];
			y = F[k][y];
		}
	}
	return max({ans,C[0][x],C[0][y]});
}

int main(){
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);
	cout.precision(10);
	cout << fixed;

	for(Long i = 0; i < MX; i++) grupo[i] = parent[i] = i;

	Long n, m, k, q, x, y, w;
	cin >> n >> m >> k >> q;

	for(Long i = 0; i < m; i++){
		cin >> x >> y >> w;
		o_adj[x].push_back(y);
		o_pes[x].push_back(w);
		o_adj[y].push_back(x);
		o_pes[y].push_back(w);
	}

	priority_queue< pair<Long, pair<Long,Long> > > pq;
	for(Long i = 1; i <= k; i++){
		dist[i][i] = 0;
		pq.push({0ll,{i,i}});
	}

	while(!pq.empty()){
		Long d = -pq.top().first;
		Long u = pq.top().second.first;
		Long v = pq.top().second.second;
		pq.pop();

		if(dist[u][v] != d) continue;

		Long gu = grupo[u];
		Long gv = grupo[v];

		if(gv > k){
			grupo[gv] = gu;
		}else{
			if(findSet(gu) != findSet(gv)){
				adj[gu].push_back(gv);
				pes[gu].push_back(d + dist[gv][v]);
				adj[gv].push_back(gu);
				pes[gv].push_back(d + dist[gv][v]);
				unionSet(gu,gv);
			}
		}

		if(gv <= k && gv != gu) continue;
		Long sz = o_adj[v].size();
		for(Long i = 0; i < sz; i++){
			Long nv = o_adj[v][i];
			Long ww = o_pes[v][i];
			if(dist[u].find(nv) == dist[u].end() || dist[u][nv] > d + ww){
				dist[u][nv] = d + ww;
				pq.push({-dist[u][nv],{u,nv}});
			}
		}
	}

	lca_init(1,k+1);

	for(Long i = 0; i < q; i++){
		cin >> x >> y;
		cout << lca(x,y) << "\n";
	}
	return 0;
}


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

const Long MX = 1e5 + 10;
const Long K = 20;

vector<Long> o_adj[MX];
vector<Long> o_pes[MX];
vector<Long> adj[MX];
vector<Long> pes[MX];

map<Long,Long> dist[MX];

Long parent[MX];
Long rnk[MX];

Long findSet(Long i){
	if(parent[i]==i){
		return i;
	}
	parent[i]=findSet(parent[i]);
	return parent[i];
}

void unionSet(Long i, Long j){
	Long x=findSet(i);
	Long y=findSet(j);
	if(y!=x){
		if(rnk[x]>rnk[y]){
			parent[y]=x;
		}else{
			parent[x]=y;
			if(rnk[x]==rnk[y]){
				rnk[y]++;
			}
		}
	}
	return;
}

Long F[K][MX];
Long C[K][MX];
Long D[MX];

void lca_dfs(Long u){
	Long sz = adj[u].size();
	for(Long i = 0; i < sz; i++){
		Long v = adj[u][i];
		if(v == F[0][u]) continue;
		F[0][v] = u;
		C[0][v] = pes[u][i];
		D[v] = D[u] + 1;
		lca_dfs(v);
	}
	return;
}

void lca_init(Long x, Long n){
	D[x] = 0;
	F[0][x] = -1;
	C[0][x] = 0;
	lca_dfs(x);
	for(Long k = 1; k < K; k++){
		for(Long x = 0; x < n; x++){
			if(F[k-1][x] < 0){
				F[k][x] = -1;
			}else{
				F[k][x] = F[k-1][F[k-1][x]];
				C[k][x] = max(C[k-1][x],C[k-1][F[k-1][x]]);
			}
		}
	}
	return;
}

Long lca(Long x, Long y){
	Long ans = 0;
	if(D[x] < D[y]) swap(x,y);
	for(Long k = K-1; k >= 0; k--){
		if(D[x] - (1ll<<k) >= D[y]){
			ans = max(ans,C[k][x]);
			x = F[k][x];
		}
	}
	if(x == y) return ans;
	for(Long k = K-1; k >= 0; k--){
		if(F[k][x] != F[k][y]){
			ans = max(ans,C[k][x]);
			ans = max(ans,C[k][y]);
			x = F[k][x];
			y = F[k][y];
		}
	}
	return max({ans,C[0][x],C[0][y]});
}

int main(){
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);
	cout.precision(10);
	cout << fixed;

	for(Long i = 0; i < MX; i++) parent[i] = i;

	Long n, m, k, q, x, y, w;
	cin >> n >> m >> k >> q;

	for(Long i = 0; i < m; i++){
		cin >> x >> y >> w;
		o_adj[x].push_back(y);
		o_pes[x].push_back(w);
		o_adj[y].push_back(x);
		o_pes[y].push_back(w);
	}

	priority_queue< pair<Long, pair<Long,Long> > > pq;
	for(Long i = 1; i <= k; i++){
		dist[i][i] = 0;
		pq.push({0ll,{i,i}});
	}

	while(!pq.empty()){
		Long d = -pq.top().first;
		Long u = pq.top().second.first;
		Long v = pq.top().second.second;
		pq.pop();

		if(dist[u][v] != d) continue;

		Long gu = findSet(u);
		Long gv = findSet(v);

		if(u != v && gu == gv) continue;

		if(u <= k && v <= k && gu != gv){
			adj[gu].push_back(gv);
			pes[gu].push_back(d);
			adj[gv].push_back(gu);
			pes[gv].push_back(d);
			unionSet(gu,gv);
		}else{
			Long sz = o_adj[v].size();
			for(Long i = 0; i < sz; i++){
				Long nv = o_adj[v][i];
				Long ww = o_pes[v][i];
				if(dist[u].find(nv) == dist[u].end() || dist[u][nv] > d + ww){
					dist[u][nv] = d + ww;
					pq.push({-dist[u][nv],{u,nv}});
				}
			}
		}
	}

	lca_init(1,k+1);

	for(Long i = 0; i < q; i++){
		cin >> x >> y;
		cout << lca(x,y) << "\n";
	}
	return 0;
}


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

const Long MX = 1e5 + 10;
const Long K = 20;

vector<Long> o_adj[MX];
vector<Long> o_pes[MX];
vector<Long> adj[MX];
vector<Long> pes[MX];

map<Long,Long> dist[MX];

Long parent[MX];
Long rnk[MX];

Long findSet(Long i){
	if(parent[i]==i){
		return i;
	}
	parent[i]=findSet(parent[i]);
	return parent[i];
}

void unionSet(Long i, Long j){
	Long x=findSet(i);
	Long y=findSet(j);
	if(y!=x){
		if(rnk[x]>rnk[y]){
			parent[y]=x;
		}else{
			parent[x]=y;
			if(rnk[x]==rnk[y]){
				rnk[y]++;
			}
		}
	}
	return;
}

Long F[K][MX];
Long C[K][MX];
Long D[MX];

void lca_dfs(Long u){
	Long sz = adj[u].size();
	for(Long i = 0; i < sz; i++){
		Long v = adj[u][i];
		if(v == F[0][u]) continue;
		F[0][v] = u;
		C[0][v] = pes[u][i];
		D[v] = D[u] + 1;
		lca_dfs(v);
	}
	return;
}

void lca_init(Long x, Long n){
	D[x] = 0;
	F[0][x] = -1;
	C[0][x] = 0;
	lca_dfs(x);
	for(Long k = 1; k < K; k++){
		for(Long x = 0; x < n; x++){
			if(F[k-1][x] < 0){
				F[k][x] = -1;
			}else{
				F[k][x] = F[k-1][F[k-1][x]];
				C[k][x] = max(C[k-1][x],C[k-1][F[k-1][x]]);
			}
		}
	}
	return;
}

Long lca(Long x, Long y){
	Long ans = 0;
	if(D[x] < D[y]) swap(x,y);
	for(Long k = K-1; k >= 0; k--){
		if(D[x] - (1ll<<k) >= D[y]){
			ans = max(ans,C[k][x]);
			x = F[k][x];
		}
	}
	if(x == y) return ans;
	for(Long k = K-1; k >= 0; k--){
		if(F[k][x] != F[k][y]){
			ans = max(ans,C[k][x]);
			ans = max(ans,C[k][y]);
			x = F[k][x];
			y = F[k][y];
		}
	}
	return max(ans,C[0][x]);
}

int main(){
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);
	cout.precision(10);
	cout << fixed;

	for(Long i = 0; i < MX; i++) parent[i] = i;

	Long n, m, k, q, x, y, w;
	cin >> n >> m >> k >> q;

	for(Long i = 0; i < m; i++){
		cin >> x >> y >> w;
		o_adj[x].push_back(y);
		o_pes[x].push_back(w);
		o_adj[y].push_back(x);
		o_pes[y].push_back(w);
	}

	priority_queue< pair<Long, pair<Long,Long> > > pq;
	for(Long i = 1; i <= k; i++){
		dist[i][i] = 0;
		pq.push({0ll,{i,i}});
	}

	while(!pq.empty()){
		Long d = -pq.top().first;
		Long u = pq.top().second.first;
		Long v = pq.top().second.second;
		pq.pop();

		if(dist[u][v] != d) continue;

		Long gu = findSet(u);
		Long gv = findSet(v);

		if(u != v && gu == gv) continue;

		if(u <= k && v <= k && gu != gv){
			adj[gu].push_back(gv);
			pes[gu].push_back(d);
			adj[gv].push_back(gu);
			pes[gv].push_back(d);
			unionSet(gu,gv);
		}else{
			Long sz = o_adj[v].size();
			for(Long i = 0; i < sz; i++){
				Long nv = o_adj[v][i];
				Long ww = o_pes[v][i];
				if(dist[u].find(nv) == dist[u].end() || dist[u][nv] > d + ww){
					dist[u][nv] = d + ww;
					pq.push({-dist[u][nv],{u,nv}});
				}
			}
		}
	}

	lca_init(1,k+1);

	for(Long i = 0; i < q; i++){
		cin >> x >> y;
		cout << lca(x,y) << "\n";
	}
	return 0;
}


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

const Long MX = 1e5 + 10;
const Long K = 20;

vector<Long> o_adj[MX];
vector<Long> o_pes[MX];
vector<Long> adj[MX];
vector<Long> pes[MX];

map<Long,Long> dist[MX];

Long parent[MX];

Long findSet(Long i){
	if(parent[i]==i){
		return i;
	}
	parent[i]=findSet(parent[i]);
	return parent[i];
}

void unionSet(Long i, Long j){
	Long x=findSet(i);
	Long y=findSet(j);
	if(y != x){
		if(dist[x].size() > dist[y].size()) swap(x,y);
		parent[x] = y;
		for(auto par : dist[x]) dist[y][par.first] = par.second;
	}
	return;
}

Long F[K][MX];
Long C[K][MX];
Long D[MX];

void lca_dfs(Long u){
	Long sz = adj[u].size();
	for(Long i = 0; i < sz; i++){
		Long v = adj[u][i];
		if(v == F[0][u]) continue;
		F[0][v] = u;
		C[0][v] = pes[u][i];
		D[v] = D[u] + 1;
		lca_dfs(v);
	}
	return;
}

void lca_init(Long x, Long n){
	D[x] = 0;
	F[0][x] = -1;
	C[0][x] = 0;
	lca_dfs(x);
	for(Long k = 1; k < K; k++){
		for(Long x = 0; x < n; x++){
			if(F[k-1][x] < 0){
				F[k][x] = -1;
			}else{
				F[k][x] = F[k-1][F[k-1][x]];
				C[k][x] = max(C[k-1][x],C[k-1][F[k-1][x]]);
			}
		}
	}
	return;
}

Long lca(Long x, Long y){
	Long ans = 0;
	if(D[x] < D[y]) swap(x,y);
	for(Long k = K-1; k >= 0; k--){
		if(D[x] - (1ll<<k) >= D[y]){
			ans = max(ans,C[k][x]);
			x = F[k][x];
		}
	}
	if(x == y) return ans;
	for(Long k = K-1; k >= 0; k--){
		if(F[k][x] != F[k][y]){
			ans = max(ans,C[k][x]);
			ans = max(ans,C[k][y]);
			x = F[k][x];
			y = F[k][y];
		}
	}
	return max({ans,C[0][x],C[0][y]});
}

int main(){
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);
	cout.precision(10);
	cout << fixed;

	for(Long i = 0; i < MX; i++) parent[i] = i;

	Long n, m, k, q, x, y, w;
	cin >> n >> m >> k >> q;

	for(Long i = 0; i < m; i++){
		cin >> x >> y >> w;
		o_adj[x].push_back(y);
		o_pes[x].push_back(w);
		o_adj[y].push_back(x);
		o_pes[y].push_back(w);
	}

	priority_queue< pair<Long, pair<Long,Long> > > pq;
	for(Long i = 1; i <= k; i++){
		dist[i][i] = 0;
		pq.push({0ll,{i,i}});
	}

	while(!pq.empty()){
		Long d = -pq.top().first;
		Long u = pq.top().second.first;
		Long v = pq.top().second.second;
		pq.pop();

		if(dist[u][v] != d) continue;

		Long gu = findSet(u);
		Long gv = findSet(v);

		if(u != v && gu == gv) continue;

		if(u <= k && v <= k && gu != gv){
			adj[gu].push_back(gv);
			pes[gu].push_back(d);
			adj[gv].push_back(gu);
			pes[gv].push_back(d);
			unionSet(gu,gv);
		}else{
			u = findSet(u);
			Long sz = o_adj[v].size();
			for(Long i = 0; i < sz; i++){
				Long nv = o_adj[v][i];
				Long ww = o_pes[v][i];
				if(dist[u].find(nv) == dist[u].end() || dist[u][nv] > d + ww){
					dist[u][nv] = d + ww;
					pq.push({-dist[u][nv],{u,nv}});
				}
			}
		}
	}

	lca_init(1,k+1);

	for(Long i = 0; i < q; i++){
		cin >> x >> y;
		cout << lca(x,y) << "\n";
	}
	return 0;
}


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

const Long MX = 1e5 + 10;
const Long K = 20;

vector<Long> o_adj[MX];
vector<Long> o_pes[MX];
vector<Long> adj[MX];
vector<Long> pes[MX];

map<Long,Long> dist[MX];

Long parent[MX];
Long rnk[MX];

Long findSet(Long i){
	if(parent[i]==i){
		return i;
	}
	parent[i]=findSet(parent[i]);
	return parent[i];
}

void unionSet(Long i, Long j){
	Long x=findSet(i);
	Long y=findSet(j);
	if(y!=x){
		if(rnk[x]>rnk[y]){
			parent[y]=x;
		}else{
			parent[x]=y;
			if(rnk[x]==rnk[y]){
				rnk[y]++;
			}
		}
	}
	return;
}

Long F[K][MX];
Long C[K][MX];
Long D[MX];

void lca_dfs(Long u){
	Long sz = adj[u].size();
	for(Long i = 0; i < sz; i++){
		Long v = adj[u][i];
		if(v == F[0][u]) continue;
		F[0][v] = u;
		C[0][v] = pes[u][i];
		D[v] = D[u] + 1;
		lca_dfs(v);
	}
	return;
}

void lca_init(Long x, Long n){
	D[x] = 0;
	F[0][x] = -1;
	C[0][x] = 0;
	lca_dfs(x);
	for(Long k = 1; k < K; k++){
		for(Long x = 0; x < n; x++){
			if(F[k-1][x] < 0){
				F[k][x] = -1;
			}else{
				F[k][x] = F[k-1][F[k-1][x]];
				C[k][x] = max(C[k-1][x],C[k-1][F[k-1][x]]);
			}
		}
	}
	return;
}

Long lca(Long x, Long y){
	Long ans = 0;
	if(D[x] < D[y]) swap(x,y);
	for(Long k = K-1; k >= 0; k--){
		if(D[x] - (1ll<<k) >= D[y]){
			ans = max(ans,C[k][x]);
			x = F[k][x];
		}
	}
	if(x == y) return ans;
	for(Long k = K-1; k >= 0; k--){
		if(F[k][x] != F[k][y]){
			ans = max(ans,C[k][x]);
			ans = max(ans,C[k][y]);
			x = F[k][x];
			y = F[k][y];
		}
	}
	return max({ans,C[0][x],C[0][y]});
}

int main(){
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);
	cout.precision(10);
	cout << fixed;

	for(Long i = 0; i < MX; i++) parent[i] = i;

	Long n, m, k, q, x, y, w;
	cin >> n >> m >> k >> q;

	for(Long i = 0; i < m; i++){
		cin >> x >> y >> w;
		o_adj[x].push_back(y);
		o_pes[x].push_back(w);
		o_adj[y].push_back(x);
		o_pes[y].push_back(w);
	}

	priority_queue< pair<Long, pair<Long,Long> > > pq;
	for(Long i = 1; i <= k; i++){
		dist[i][i] = 0;
		pq.push({0ll,{i,i}});
	}

	while(!pq.empty()){
		Long d = -pq.top().first;
		Long u = pq.top().second.first;
		Long v = pq.top().second.second;
		pq.pop();

		if(dist[u][v] != d) continue;

		Long gu = findSet(u);
		Long gv = findSet(v);

		if(u != v && gu == gv) continue;
		if(u != v && u != gu) continue;

		if(u <= k && v <= k && gu != gv){
			adj[gu].push_back(gv);
			pes[gu].push_back(d);
			adj[gv].push_back(gu);
			pes[gv].push_back(d);
			unionSet(gu,gv);
		}else{
			u = findSet(u);
			Long sz = o_adj[v].size();
			for(Long i = 0; i < sz; i++){
				Long nv = o_adj[v][i];
				Long ww = o_pes[v][i];
				if(dist[u].find(nv) == dist[u].end() || dist[u][nv] > d + ww){
					dist[u][nv] = d + ww;
					pq.push({-dist[u][nv],{u,nv}});
				}
			}
		}
	}

	lca_init(1,k+1);

	for(Long i = 0; i < q; i++){
		cin >> x >> y;
		cout << lca(x,y) << "\n";
	}
	return 0;
}


#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<ll, int> pii;

#define fi first
#define se second
#define mp make_pair
#define fastIO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

const int N = (int)1e5 + 9;
const int Q = (int)3e5 + 9;
vector<pii> T[N];
ll di[N];

struct Edge{
  int a;
  int b;
  ll ww;
  bool operator< (const Edge &T){
    return ww < T.ww;
  }
};

set<int> qq[N];
int par[N];
int ret[Q];

int fin(int x){
  if(par[x]==x)
    return x;
  return par[x]=fin(par[x]);
}

void unite(int a, int b, int ww){
  a=fin(a);
  b=fin(b);
  if(a==b) return;
  if(qq[a].size() > qq[b].size()) swap(a,b);
  for(auto x : qq[a]){
    if(qq[b].count(x)){
      ret[x]=ww;
    }
    qq[b].insert(x);
  }
  qq[a].clear();
  par[a]=b;
}

int main(){
  fastIO;
  int n, m, k, q;
  cin >> n >> m >> k >> q;
  int u[m], v[m], w[m];
  for(int i = 0 ; i < m ; i ++ ){
    cin >> u[i] >> v[i] >> w[i];
    T[u[i]].push_back(mp(v[i],w[i]));
    T[v[i]].push_back(mp(u[i],w[i]));
  }
  for(int i = 1; i <= n; i ++ )di[i] = (ll)1e18;
  priority_queue<pii, vector<pii>, greater<pii>> ff;
  for(int i = 1; i <= k ; i ++ ){
    ff.push(mp(0, i));
    di[i]=0;
  }
  int node;
  ll dis;
  while(!ff.empty()){
    node = ff.top().se;
    dis = ff.top().fi;
    ff.pop();
    if(dis != di[node]){
      continue;
    }
    for(auto x : T[node]){

      if(di[x.fi] > dis + x.se){
        di[x.fi] = dis + x.se;
        ff.push(mp(di[x.fi], x.fi));
      }
    }
  }
  vector<Edge> ri;
  for(int i = 0 ; i < m ; i ++ ){
    ri.push_back({u[i], v[i], w[i] + di[u[i]] + di[v[i]]});
  }
  sort(ri.begin(), ri.end());
  for(int i = 1; i <= n; i ++ )
    par[i]=i;
  int iq, jq;
  for(int i = 0 ; i < q; i ++ ){
    cin >> iq >> jq;
    qq[iq].insert(i);
    qq[jq].insert(i);
  }
  for(int i = 0 ; i < m ; i ++ ){
    unite(ri[i].a, ri[i].b, ri[i].ww);
  }
  for(int i = 0 ; i < q; i ++ )
    cout << ret[i] << "\n";
  return 0;
}


#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<ll, int> pii;

#define fi first
#define se second
#define mp make_pair
#define fastIO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

const int N = (int)1e5 + 9;
const int Q = (int)3e5 + 9;
vector<pii> T[N];
ll di[N];

struct Edge{
  int a;
  int b;
  ll ww;
  bool operator< (const Edge &T){
    return ww < T.ww;
  }
};

set<int> qq[N];
int par[N];
int ret[Q];

int fin(int x){
  if(par[x]==x)
    return x;
  return par[x]=fin(par[x]);
}

void unite(int a, int b, ll ww){
  a=fin(a);
  b=fin(b);
  if(a==b) return;
  if(qq[a].size() > qq[b].size()) swap(a,b);
  for(auto x : qq[a]){
    if(qq[b].count(x)){
      ret[x]=ww;
    }
    qq[b].insert(x);
  }
  qq[a].clear();
  par[a]=b;
}

int main(){
  fastIO;
  int n, m, k, q;
  cin >> n >> m >> k >> q;
  int u[m], v[m], w[m];
  for(int i = 0 ; i < m ; i ++ ){
    cin >> u[i] >> v[i] >> w[i];
    T[u[i]].push_back(mp(v[i],w[i]));
    T[v[i]].push_back(mp(u[i],w[i]));
  }
  for(int i = 1; i <= n; i ++ )di[i] = (ll)1e18;
  priority_queue<pii, vector<pii>, greater<pii>> ff;
  for(int i = 1; i <= k ; i ++ ){
    ff.push(mp(0, i));
    di[i]=0;
  }
  int node;
  ll dis;
  while(!ff.empty()){
    node = ff.top().se;
    dis = ff.top().fi;
    ff.pop();
    if(dis != di[node]){
      continue;
    }
    for(auto x : T[node]){

      if(di[x.fi] > dis + x.se){
        di[x.fi] = dis + x.se;
        ff.push(mp(di[x.fi], x.fi));
      }
    }
  }
  vector<Edge> ri;
  for(int i = 0 ; i < m ; i ++ ){
    ri.push_back({u[i], v[i], w[i] + di[u[i]] + di[v[i]]});
  }
  sort(ri.begin(), ri.end());
  for(int i = 1; i <= n; i ++ )
    par[i]=i;
  int iq, jq;
  for(int i = 0 ; i < q; i ++ ){
    cin >> iq >> jq;
    qq[iq].insert(i);
    qq[jq].insert(i);
  }
  for(int i = 0 ; i < m ; i ++ ){
    unite(ri[i].a, ri[i].b, ri[i].ww);
  }
  for(int i = 0 ; i < q; i ++ )
    cout << ret[i] << "\n";
  return 0;
}


#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<ll, int> pii;

#define fi first
#define se second
#define mp make_pair
#define fastIO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

const int N = (int)1e5 + 9;
const int Q = (int)3e5 + 9;
vector<pii> T[N];
ll di[N];

struct Edge{
  int a;
  int b;
  ll ww;
  bool operator< (const Edge &T){
    return ww < T.ww;
  }
};

set<int> qq[N];
int par[N];
ll ret[Q];

int fin(int x){
  if(par[x]==x)
    return x;
  return par[x]=fin(par[x]);
}

void unite(int a, int b, ll ww){
  a=fin(a);
  b=fin(b);
  if(a==b) return;
  if(qq[a].size() > qq[b].size()) swap(a,b);
  for(auto x : qq[a]){
    if(qq[b].count(x)){
      ret[x]=ww;
    }
    qq[b].insert(x);
  }
  qq[a].clear();
  par[a]=b;
}

int main(){
  fastIO;
  int n, m, k, q;
  cin >> n >> m >> k >> q;
  int u[m], v[m], w[m];
  for(int i = 0 ; i < m ; i ++ ){
    cin >> u[i] >> v[i] >> w[i];
    T[u[i]].push_back(mp(v[i],w[i]));
    T[v[i]].push_back(mp(u[i],w[i]));
  }
  for(int i = 1; i <= n; i ++ )di[i] = (ll)1e18;
  priority_queue<pii, vector<pii>, greater<pii>> ff;
  for(int i = 1; i <= k ; i ++ ){
    ff.push(mp(0, i));
    di[i]=0;
  }
  int node;
  ll dis;
  while(!ff.empty()){
    node = ff.top().se;
    dis = ff.top().fi;
    ff.pop();
    if(dis != di[node]){
      continue;
    }
    for(auto x : T[node]){

      if(di[x.fi] > dis + x.se){
        di[x.fi] = dis + x.se;
        ff.push(mp(di[x.fi], x.fi));
      }
    }
  }
  vector<Edge> ri;
  for(int i = 0 ; i < m ; i ++ ){
    ri.push_back({u[i], v[i], w[i] + di[u[i]] + di[v[i]]});
  }
  sort(ri.begin(), ri.end());
  for(int i = 1; i <= n; i ++ )
    par[i]=i;
  int iq, jq;
  for(int i = 0 ; i < q; i ++ ){
    cin >> iq >> jq;
    qq[iq].insert(i);
    qq[jq].insert(i);
  }
  for(int i = 0 ; i < m ; i ++ ){
    unite(ri[i].a, ri[i].b, ri[i].ww);
  }
  for(int i = 0 ; i < q; i ++ )
    cout << ret[i] << "\n";
  return 0;
}


#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<ll, int> pii;

#define fi first
#define se second
#define mp make_pair
#define fastIO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

const int N = (int)1e5 + 9;
vector<pii> T[N];
ll di[N];

struct Edge{
  int a;
  int b;
  ll ww;
  bool operator< (const Edge &T){
    return ww < T.ww;
  }
};

set<int> qq[N];
int par[N];
int ret[N];

int fin(int x){
  if(par[x]==x)
    return x;
  return par[x]=fin(par[x]);
}

void unite(int a, int b, int ww){
  a=fin(a);
  b=fin(b);
  if(a==b) return;
  if(qq[a].size() > qq[b].size()) swap(a,b);
  for(auto x : qq[a]){
    if(qq[b].count(x)){
      ret[x]=ww;
    }
    qq[b].insert(x);
  }
  qq[a].clear();
  par[a]=b;
}

int main(){
  fastIO;
  int n, m, k, q;
  cin >> n >> m >> k >> q;
  int u[m], v[m], w[m];
  for(int i = 0 ; i < m ; i ++ ){
    cin >> u[i] >> v[i] >> w[i];
    T[u[i]].push_back(mp(v[i],w[i]));
    T[v[i]].push_back(mp(u[i],w[i]));
  }
  for(int i = 1; i <= n; i ++ )di[i] = (ll)1e18;
  priority_queue<pii, vector<pii>, greater<pii>> ff;
  for(int i = 1; i <= k ; i ++ ){
    ff.push(mp(0, i));
    di[i]=0;
  }
  int node;
  ll dis;
  while(!ff.empty()){
    node = ff.top().se;
    dis = ff.top().fi;
    ff.pop();
    if(dis != di[node]){
      continue;
    }
    for(auto x : T[node]){

      if(di[x.fi] > dis + x.se){
        di[x.fi] = dis + x.se;
        ff.push(mp(di[x.fi], x.fi));
      }
    }
  }
  vector<Edge> ri;
  for(int i = 0 ; i < m ; i ++ ){
    ri.push_back({u[i], v[i], w[i] + di[u[i]] + di[v[i]]});
  }
  sort(ri.begin(), ri.end());
  for(int i = 1; i <= n; i ++ )
    par[i]=i;
  int iq, jq;
  for(int i = 0 ; i < q; i ++ ){
    cin >> iq >> jq;
    qq[iq].insert(i);
    qq[jq].insert(i);
  }
  for(int i = 0 ; i < m ; i ++ ){
    unite(ri[i].a, ri[i].b, ri[i].ww);
  }
  for(int i = 0 ; i < q; i ++ )
    cout << ret[i] << "\n";
  return 0;
}


#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<ll, int> pii;

#define fi first
#define se second
#define mp make_pair
#define fastIO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

const int N = (int)1e5 + 9;
const int Q = (int)3e5 + 9;
vector<pii> T[N];
ll di[N];

struct Edge{
  int a;
  int b;
  ll ww;
  bool operator< (const Edge &T){
    return ww < T.ww;
  }
};

set<int> qq[N];
int par[N];
ll ret[Q];

int fin(int x){
  if(par[x]==x)
    return x;
  return par[x]=fin(par[x]);
}

void unite(int a, int b, int ww){
  a=fin(a);
  b=fin(b);
  if(a==b) return;
  if(qq[a].size() > qq[b].size()) swap(a,b);
  for(auto x : qq[a]){
    if(qq[b].count(x)){
      ret[x]=ww;
    }
    qq[b].insert(x);
  }
  qq[a].clear();
  par[a]=b;
}

int main(){
  fastIO;
  int n, m, k, q;
  cin >> n >> m >> k >> q;
  int u[m], v[m], w[m];
  for(int i = 0 ; i < m ; i ++ ){
    cin >> u[i] >> v[i] >> w[i];
    T[u[i]].push_back(mp(v[i],w[i]));
    T[v[i]].push_back(mp(u[i],w[i]));
  }
  for(int i = 1; i <= n; i ++ )di[i] = (ll)1e18;
  priority_queue<pii, vector<pii>, greater<pii>> ff;
  for(int i = 1; i <= k ; i ++ ){
    ff.push(mp(0, i));
    di[i]=0;
  }
  int node;
  ll dis;
  while(!ff.empty()){
    node = ff.top().se;
    dis = ff.top().fi;
    ff.pop();
    if(dis != di[node]){
      continue;
    }
    for(auto x : T[node]){

      if(di[x.fi] > dis + x.se){
        di[x.fi] = dis + x.se;
        ff.push(mp(di[x.fi], x.fi));
      }
    }
  }
  vector<Edge> ri;
  for(int i = 0 ; i < m ; i ++ ){
    ri.push_back({u[i], v[i], w[i] + di[u[i]] + di[v[i]]});
  }
  sort(ri.begin(), ri.end());
  for(int i = 1; i <= n; i ++ )
    par[i]=i;
  int iq, jq;
  for(int i = 0 ; i < q; i ++ ){
    cin >> iq >> jq;
    qq[iq].insert(i);
    qq[jq].insert(i);
  }
  for(int i = 0 ; i < m ; i ++ ){
    unite(ri[i].a, ri[i].b, ri[i].ww);
  }
  for(int i = 0 ; i < q; i ++ )
    cout << ret[i] << "\n";
  return 0;
}


#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace std;
using namespace __gnu_pbds;

#define fto(i, s, e) for(int i = (s); i <= (e); ++i)
#define fto1(i, s, e) for(int i = (s); i < (e); ++i)
#define fdto(i, s, e) for(int i = (s); i >= (e); --i)
#define fat(i, a) for(auto i : a)
#define fit(it, var) for(auto it = (var).begin(); it != (var).end(); ++it)
#define frit(it, var) for(auto it = (var).rbegin(); it != (var).rend(); ++it)

#define bc __builtin_popcountll
#define isbit(x, bit) (((x >> bit) & 1) != 0)
#define onbit(x, bit) (x | (1LL << bit))
#define offbit(x, bit) (x & ~(1LL << bit))
#define y1 ansdj
#define endl '\n'
#define _bug(...) bug(__func__, __LINE__, __VA_ARGS__)

#define li long long
#define cd complex<double>
#define ii pair<int, int>
#define ll pair<long, long>
#define x first
#define y second
#define pb push_back
#define sz(v) int((v).size())
#define all(v) (v).begin(), (v).end()

template<class T, class Cmp = less<T>> using oss = tree<T, null_type, Cmp, rb_tree_tag, tree_order_statistics_node_update>;

template<class T1, class T2> ostream& operator<<(ostream &os, pair<T1, T2> const &v) {
	return os << '(' << v.x << ", " << v.y << ')';
}

template<class T> ostream& operator<<(ostream &os, vector<T> const &v) {
	fto1 (i, 0, sz(v)) { os << v[i]; if (i < sz(v)-1) os << ' '; }
	return os;
}

template<class T> void buga(T const &v, int l, int r) { fto (i, l, r) { cout << v[i] << " \n"[i == r]; } }

template<class T> void bug(T const &v) { cout << v << endl; }
template<class T, class... Args> void bug(T const &v, Args const&... args) { cout << v << ' '; bug(args...); }

double const pi = acos(-1);
#define oo 1000000007
#define OO 1000000000000000003LL
int const maxn = 2e5+3;

int n, m, k, query;
int p[maxn], depth[maxn], pre[maxn], root[maxn][20];
li d[maxn], f[maxn][20];
vector<pair<int, li>> g[maxn];
vector<ii> ke[maxn];
vector<pair<li, ii>> edge;

int Par(int u) { return p[u] < 0 ? u : p[u] = Par(p[u]); }

bool Union(int u, int v) {
	u = Par(u); v = Par(v);
	if (u == v) return 0;
	if (p[u] > p[v]) swap(u, v);
	p[u] += p[v];
	p[v] = u;
	return 1;
}

void kruskal() {
	fat (e, edge) {
		ii node = e.y;
		if (Union(node.x, node.y)) {
			g[node.x].pb({node.y, e.x});
			g[node.y].pb({node.x, e.x});
		}
	}
}

void dfs(int u) {
	fto (i, 1, 16) {
		root[u][i] = root[root[u][i-1]][i-1];
		f[u][i] = max(f[u][i-1], f[root[u][i-1]][i-1]);
	}
	fat (v, g[u]) {
		if (v.x == root[u][0]) continue;
		root[v.x][0] = u;
		f[v.x][0] = v.y;
		depth[v.x] = depth[u] + 1;
		dfs(v.x);
	}
}

li lca(int u, int v) {
	if (depth[u] < depth[v]) swap(u, v);
	int dt = depth[u] - depth[v];
	li ans = 0;
	fto (i, 0, 16) if (isbit(dt, i)) {
		ans = max(ans, f[u][i]);
		u = root[u][i];
	}
	if (u == v) return ans;
	fdto (i, 16, 0) if (root[u][i] != root[v][i]) {
		ans = max({ans, f[u][i], f[v][i]});
		u = root[u][i];
		v = root[v][i];
	}
	return max({ans, f[u][0], f[v][0]});
}

int main() {
	#ifdef KITTENS
		freopen("main.inp", "r", stdin);
		freopen("main.out", "w", stdout);
	#endif
	ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);

	scanf("%d%d%d%d", &n, &m, &k, &query);

	int u, v, w;
	fto (i, 1, m) {
		scanf("%d%d%d", &u, &v, &w);
		ke[u].pb({v, w});
		ke[v].pb({u, w});
	}

	priority_queue<pair<li, int>, vector<pair<li, int>>, greater<pair<li, int>>> q;
	fto (i, 1, n) {
		if (i <= k) q.push({0, i});
		else d[i] = OO;
		p[i] = -1;
	}

	while (!q.empty()) {
		u = q.top().y;
		q.pop();
		if (d[u] > 0) continue;
		fat (v, ke[u]) {
			li total = d[u] + v.y;
			if (d[v.x] > total) {
				d[v.x] = total;
				pre[v.x] = u;
				q.push({total, v.x});
			}
		}
	}

	fto (u, 1, n) fat (v, ke[u]) {
		if (v.x != pre[u]) edge.pb({d[u] + d[v.x] + v.y, {u, v.x}});
	}

	sort(all(edge));
	kruskal();
	dfs(1);

	while (query--) {
		scanf("%d%d", &u, &v);
		bug(lca(u, v));
	}

	#ifdef KITTENS
		cerr << 0.001*clock() << endl;
	#endif
	return 0;
}


#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace std;
using namespace __gnu_pbds;

#define fto(i, s, e) for(int i = (s); i <= (e); ++i)
#define fto1(i, s, e) for(int i = (s); i < (e); ++i)
#define fdto(i, s, e) for(int i = (s); i >= (e); --i)
#define fat(i, a) for(auto i : a)
#define fit(it, var) for(auto it = (var).begin(); it != (var).end(); ++it)
#define frit(it, var) for(auto it = (var).rbegin(); it != (var).rend(); ++it)

#define bc __builtin_popcountll
#define isbit(x, bit) (((x >> bit) & 1) != 0)
#define onbit(x, bit) (x | (1LL << bit))
#define offbit(x, bit) (x & ~(1LL << bit))
#define y1 ansdj
#define endl '\n'
#define _bug(...) bug(__func__, __LINE__, __VA_ARGS__)

#define li long long
#define cd complex<double>
#define ii pair<int, int>
#define ll pair<long, long>
#define x first
#define y second
#define pb push_back
#define sz(v) int((v).size())
#define all(v) (v).begin(), (v).end()

template<class T, class Cmp = less<T>> using oss = tree<T, null_type, Cmp, rb_tree_tag, tree_order_statistics_node_update>;

template<class T1, class T2> ostream& operator<<(ostream &os, pair<T1, T2> const &v) {
	return os << '(' << v.x << ", " << v.y << ')';
}

template<class T> ostream& operator<<(ostream &os, vector<T> const &v) {
	fto1 (i, 0, sz(v)) { os << v[i]; if (i < sz(v)-1) os << ' '; }
	return os;
}

template<class T> void buga(T const &v, int l, int r) { fto (i, l, r) { cout << v[i] << " \n"[i == r]; } }

template<class T> void bug(T const &v) { cout << v << endl; }
template<class T, class... Args> void bug(T const &v, Args const&... args) { cout << v << ' '; bug(args...); }

double const pi = acos(-1);
#define oo 1000000007
#define OO 1000000000000000003LL
int const maxn = 2e5+3;

int n, m, k, query;
int p[maxn], depth[maxn], pre[maxn], check[maxn], root[maxn][20];
li d[maxn], f[maxn][20];
vector<pair<int, li>> g[maxn];
vector<ii> ke[maxn];
vector<pair<li, ii>> edge;

int Par(int u) { return p[u] < 0 ? u : p[u] = Par(p[u]); }

bool Union(int u, int v) {
	u = Par(u); v = Par(v);
	if (u == v) return 0;
	if (p[u] > p[v]) swap(u, v);
	p[u] += p[v];
	p[v] = u;
	return 1;
}

void kruskal() {
	fat (e, edge) {
		ii node = e.y;
		if (Union(node.x, node.y)) {
			g[node.x].pb({node.y, e.x});
			g[node.y].pb({node.x, e.x});
		}
	}
}

void dfs(int u) {
	fto (i, 1, 16) {
		root[u][i] = root[root[u][i-1]][i-1];
		f[u][i] = max(f[u][i-1], f[root[u][i-1]][i-1]);
	}
	fat (v, g[u]) {
		if (v.x == root[u][0]) continue;
		root[v.x][0] = u;
		f[v.x][0] = v.y;
		depth[v.x] = depth[u] + 1;
		dfs(v.x);
	}
}

li lca(int u, int v) {
	if (depth[u] < depth[v]) swap(u, v);
	int dt = depth[u] - depth[v];
	li ans = 0;
	fto (i, 0, 16) if (isbit(dt, i)) {
		ans = max(ans, f[u][i]);
		u = root[u][i];
	}
	if (u == v) return ans;
	fdto (i, 16, 0) if (root[u][i] != root[v][i]) {
		ans = max({ans, f[u][i], f[v][i]});
		u = root[u][i];
		v = root[v][i];
	}
	return max({ans, f[u][0], f[v][0]});
}

int main() {
	#ifdef KITTENS
		freopen("main.inp", "r", stdin);
		freopen("main.out", "w", stdout);
	#endif
	ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);

	scanf("%d%d%d%d", &n, &m, &k, &query);

	int u, v, w;
	fto (i, 1, m) {
		scanf("%d%d%d", &u, &v, &w);
		ke[u].pb({v, w});
		ke[v].pb({u, w});
	}

	priority_queue<pair<li, int>, vector<pair<li, int>>, greater<pair<li, int>>> q;
	fto (i, 1, n) {
		if (i <= k) q.push({0, i});
		else d[i] = OO;
		p[i] = -1;
	}

	while (!q.empty()) {
		u = q.top().y;
		q.pop();
		if (check[u]) continue;
		fat (v, ke[u]) {
			li total = d[u] + v.y;
			if (d[v.x] > total) {
				d[v.x] = total;
				pre[v.x] = u;
				q.push({total, v.x});
			}
		}
		check[u] = 1;
	}

	fto (u, 1, n) fat (v, ke[u]) {
		if (v.x != pre[u]) edge.pb({d[u] + d[v.x] + v.y, {u, v.x}});
	}

	sort(all(edge));
	kruskal();
	dfs(1);

	while (query--) {
		scanf("%d%d", &u, &v);
		bug(lca(u, v));
	}

	#ifdef KITTENS
		cerr << 0.001*clock() << endl;
	#endif
	return 0;
}


#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace std;
using namespace __gnu_pbds;

#define fto(i, s, e) for(int i = (s); i <= (e); ++i)
#define fto1(i, s, e) for(int i = (s); i < (e); ++i)
#define fdto(i, s, e) for(int i = (s); i >= (e); --i)
#define fat(i, a) for(auto i : a)
#define fit(it, var) for(auto it = (var).begin(); it != (var).end(); ++it)
#define frit(it, var) for(auto it = (var).rbegin(); it != (var).rend(); ++it)

#define bc __builtin_popcountll
#define isbit(x, bit) (((x >> bit) & 1) != 0)
#define onbit(x, bit) (x | (1LL << bit))
#define offbit(x, bit) (x & ~(1LL << bit))
#define y1 ansdj
#define endl '\n'
#define _bug(...) bug(__func__, __LINE__, __VA_ARGS__)

#define li long long
#define cd complex<double>
#define ii pair<int, int>
#define ll pair<long, long>
#define x first
#define y second
#define pb push_back
#define sz(v) int((v).size())
#define all(v) (v).begin(), (v).end()

template<class T, class Cmp = less<T>> using oss = tree<T, null_type, Cmp, rb_tree_tag, tree_order_statistics_node_update>;

template<class T1, class T2> ostream& operator<<(ostream &os, pair<T1, T2> const &v) {
	return os << '(' << v.x << ", " << v.y << ')';
}

template<class T> ostream& operator<<(ostream &os, vector<T> const &v) {
	fto1 (i, 0, sz(v)) { os << v[i]; if (i < sz(v)-1) os << ' '; }
	return os;
}

template<class T> void buga(T const &v, int l, int r) { fto (i, l, r) { cout << v[i] << " \n"[i == r]; } }

template<class T> void bug(T const &v) { cout << v << endl; }
template<class T, class... Args> void bug(T const &v, Args const&... args) { cout << v << ' '; bug(args...); }

double const pi = acos(-1);
#define oo 1000000007
#define OO 1000000000000000003LL
int const maxn = 2e5+3;

int n, m, k, query;
int p[maxn], depth[maxn], root[maxn][20];
li d[maxn], f[maxn][20];
vector<pair<int, li>> g[maxn];
vector<ii> ke[maxn];
vector<pair<li, ii>> edge;

int Par(int u) { return p[u] < 0 ? u : p[u] = Par(p[u]); }

bool Union(int u, int v) {
	u = Par(u); v = Par(v);
	if (u == v) return 0;
	if (p[u] > p[v]) swap(u, v);
	p[u] += p[v];
	p[v] = u;
	return 1;
}

void kruskal() {
	fat (e, edge) {
		ii node = e.y;
		if (Union(node.x, node.y)) {
			g[node.x].pb({node.y, e.x});
			g[node.y].pb({node.x, e.x});
		}
	}
}

void dfs(int u) {
	fto (i, 1, 16) {
		root[u][i] = root[root[u][i-1]][i-1];
		f[u][i] = max(f[u][i-1], f[root[u][i-1]][i-1]);
	}
	fat (v, g[u]) {
		if (v.x == root[u][0]) continue;
		root[v.x][0] = u;
		f[v.x][0] = v.y;
		depth[v.x] = depth[u] + 1;
		dfs(v.x);
	}
}

li lca(int u, int v) {
	if (depth[u] < depth[v]) swap(u, v);
	int dt = depth[u] - depth[v];
	li ans = 0;
	fto (i, 0, 16) if (isbit(dt, i)) {
		ans = max(ans, f[u][i]);
		u = root[u][i];
	}
	if (u == v) return ans;
	fdto (i, 16, 0) if (root[u][i] != root[v][i]) {
		ans = max({ans, f[u][i], f[v][i]});
		u = root[u][i];
		v = root[v][i];
	}
	return max({ans, f[u][0], f[v][0]});
}

int main() {
	#ifdef KITTENS
		freopen("main.inp", "r", stdin);
		freopen("main.out", "w", stdout);
	#endif
	ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);

	cin >> n >> m >> k >> query;

	int u, v, w;
	fto (i, 1, m) {
		cin >> u >> v >> w;
		ke[u].pb({v, w});
		ke[v].pb({u, w});
	}

	priority_queue<ll, vector<ll>, greater<ll>> q;
	fto (i, 1, n) {
		if (i <= k) q.push({0, i});
		else d[i] = OO;
		p[i] = -1;
	}

	while (!q.empty()) {
		u = q.top().y;
		q.pop();
		fat (v, ke[u]) {
			li total = d[u] + v.y;
			if (d[v.x] > total) {
				d[v.x] = total;
				q.push({total, v.x});
			}
		}
	}

	fto (u, 1, n) fat (v, ke[u]) {
		edge.pb({d[u] + d[v.x] + v.y, {u, v.x}});
	}

	sort(all(edge));
	kruskal();
	dfs(1);

	while (query--) {
		cin >> u >> v;
		bug(lca(u, v));
	}

	#ifdef KITTENS
		cerr << 0.001*clock() << endl;
	#endif
	return 0;
}


#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace std;
using namespace __gnu_pbds;

#define fto(i, s, e) for(int i = (s); i <= (e); ++i)
#define fto1(i, s, e) for(int i = (s); i < (e); ++i)
#define fdto(i, s, e) for(int i = (s); i >= (e); --i)
#define fat(i, a) for(auto i : a)
#define fit(it, var) for(auto it = (var).begin(); it != (var).end(); ++it)
#define frit(it, var) for(auto it = (var).rbegin(); it != (var).rend(); ++it)

#define bc __builtin_popcountll
#define isbit(x, bit) (((x >> bit) & 1) != 0)
#define onbit(x, bit) (x | (1LL << bit))
#define offbit(x, bit) (x & ~(1LL << bit))
#define y1 ansdj
#define endl '\n'
#define _bug(...) bug(__func__, __LINE__, __VA_ARGS__)

#define li long long
#define cd complex<double>
#define ii pair<int, int>
#define ll pair<long, long>
#define x first
#define y second
#define pb push_back
#define sz(v) int((v).size())
#define all(v) (v).begin(), (v).end()

template<class T, class Cmp = less<T>> using oss = tree<T, null_type, Cmp, rb_tree_tag, tree_order_statistics_node_update>;

template<class T1, class T2> ostream& operator<<(ostream &os, pair<T1, T2> const &v) {
	return os << '(' << v.x << ", " << v.y << ')';
}

template<class T> ostream& operator<<(ostream &os, vector<T> const &v) {
	fto1 (i, 0, sz(v)) { os << v[i]; if (i < sz(v)-1) os << ' '; }
	return os;
}

template<class T> void buga(T const &v, int l, int r) { fto (i, l, r) { cout << v[i] << " \n"[i == r]; } }

template<class T> void bug(T const &v) { cout << v << endl; }
template<class T, class... Args> void bug(T const &v, Args const&... args) { cout << v << ' '; bug(args...); }

double const pi = acos(-1);
#define oo 1000000007
#define OO 1000000000000000003LL
int const maxn = 2e5+3;

int n, m, k, query;
int p[maxn], depth[maxn], check[maxn], root[maxn][20];
li d[maxn], f[maxn][20];
vector<pair<int, li>> g[maxn];
vector<ii> ke[maxn];
vector<pair<li, ii>> edge;

int Par(int u) { return p[u] < 0 ? u : p[u] = Par(p[u]); }

bool Union(int u, int v) {
	u = Par(u); v = Par(v);
	if (u == v) return 0;
	if (p[u] > p[v]) swap(u, v);
	p[u] += p[v];
	p[v] = u;
	return 1;
}

void kruskal() {
	fat (e, edge) {
		ii node = e.y;
		if (Union(node.x, node.y)) {
			g[node.x].pb({node.y, e.x});
			g[node.y].pb({node.x, e.x});
		}
	}
}

void dfs(int u) {
	fto (i, 1, 16) {
		root[u][i] = root[root[u][i-1]][i-1];
		f[u][i] = max(f[u][i-1], f[root[u][i-1]][i-1]);
	}
	fat (v, g[u]) {
		if (v.x == root[u][0]) continue;
		root[v.x][0] = u;
		f[v.x][0] = v.y;
		depth[v.x] = depth[u] + 1;
		dfs(v.x);
	}
}

li lca(int u, int v) {
	if (depth[u] < depth[v]) swap(u, v);
	int dt = depth[u] - depth[v];
	li ans = 0;
	fto (i, 0, 16) if (isbit(dt, i)) {
		ans = max(ans, f[u][i]);
		u = root[u][i];
	}
	if (u == v) return ans;
	fdto (i, 16, 0) if (root[u][i] != root[v][i]) {
		ans = max({ans, f[u][i], f[v][i]});
		u = root[u][i];
		v = root[v][i];
	}
	return max({ans, f[u][0], f[v][0]});
}

int main() {
	#ifdef KITTENS
		freopen("main.inp", "r", stdin);
		freopen("main.out", "w", stdout);
	#endif
	ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);

	scanf("%d%d%d%d", &n, &m, &k, &query);

	int u, v, w;
	fto (i, 1, m) {
		scanf("%d%d%d", &u, &v, &w);
		ke[u].pb({v, w});
		ke[v].pb({u, w});
	}

	priority_queue<pair<li, int>, vector<pair<li, int>>, greater<pair<li, int>>> q;
	fto (i, 1, n) {
		if (i <= k) q.push({0, i});
		else d[i] = OO;
		p[i] = -1;
	}

	while (!q.empty()) {
		u = q.top().y;
		q.pop();
		if (check[u]) continue;
		fat (v, ke[u]) {
			li total = d[u] + v.y;
			if (d[v.x] > total) {
				d[v.x] = total;
				q.push({total, v.x});
			}
		}
		check[u] = 1;
	}

	fto (u, 1, n) fat (v, ke[u]) {
		edge.pb({d[u] + d[v.x] + v.y, {u, v.x}});
	}

	sort(all(edge));
	kruskal();
	dfs(1);

	while (query--) {
		scanf("%d%d", &u, &v);
		bug(lca(u, v));
	}

	#ifdef KITTENS
		cerr << 0.001*clock() << endl;
	#endif
	return 0;
}


#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace std;
using namespace __gnu_pbds;

#define fto(i, s, e) for(int i = (s); i <= (e); ++i)
#define fto1(i, s, e) for(int i = (s); i < (e); ++i)
#define fdto(i, s, e) for(int i = (s); i >= (e); --i)
#define fat(i, a) for(auto i : a)
#define fit(it, var) for(auto it = (var).begin(); it != (var).end(); ++it)
#define frit(it, var) for(auto it = (var).rbegin(); it != (var).rend(); ++it)

#define bc __builtin_popcountll
#define isbit(x, bit) (((x >> bit) & 1) != 0)
#define onbit(x, bit) (x | (1LL << bit))
#define offbit(x, bit) (x & ~(1LL << bit))
#define y1 ansdj
#define endl '\n'
#define _bug(...) bug(__func__, __LINE__, __VA_ARGS__)

#define li long long
#define cd complex<double>
#define ii pair<int, int>
#define ll pair<long, long>
#define x first
#define y second
#define pb push_back
#define sz(v) int((v).size())
#define all(v) (v).begin(), (v).end()

template<class T, class Cmp = less<T>> using oss = tree<T, null_type, Cmp, rb_tree_tag, tree_order_statistics_node_update>;

template<class T1, class T2> ostream& operator<<(ostream &os, pair<T1, T2> const &v) {
	return os << '(' << v.x << ", " << v.y << ')';
}

template<class T> ostream& operator<<(ostream &os, vector<T> const &v) {
	fto1 (i, 0, sz(v)) { os << v[i]; if (i < sz(v)-1) os << ' '; }
	return os;
}

template<class T> void buga(T const &v, int l, int r) { fto (i, l, r) { cout << v[i] << " \n"[i == r]; } }

template<class T> void bug(T const &v) { cout << v << endl; }
template<class T, class... Args> void bug(T const &v, Args const&... args) { cout << v << ' '; bug(args...); }

double const pi = acos(-1);
#define oo 1000000007
#define OO 1000000000000000003LL
int const maxn = 2e5+3;

int n, m, k, query;
int p[maxn], depth[maxn], root[maxn][20];
li d[maxn], f[maxn][20];
vector<pair<int, li>> g[maxn];
vector<ii> ke[maxn];
vector<pair<li, ii>> edge;

int Par(int u) { return p[u] < 0 ? u : p[u] = Par(p[u]); }

bool Union(int u, int v) {
	u = Par(u); v = Par(v);
	if (u == v) return 0;
	if (p[u] > p[v]) swap(u, v);
	p[u] += p[v];
	p[v] = u;
	return 1;
}

void kruskal() {
	fat (e, edge) {
		ii node = e.y;
		if (Union(node.x, node.y)) {
			g[node.x].pb({node.y, e.x});
			g[node.y].pb({node.x, e.x});
		}
	}
}

void dfs(int u) {
	fto (i, 1, 16) {
		root[u][i] = root[root[u][i-1]][i-1];
		f[u][i] = max(f[u][i-1], f[root[u][i-1]][i-1]);
	}
	fat (v, g[u]) {
		if (v.x == root[u][0]) continue;
		root[v.x][0] = u;
		f[v.x][0] = v.y;
		depth[v.x] = depth[u] + 1;
		dfs(v.x);
	}
}

li lca(int u, int v) {
	if (depth[u] < depth[v]) swap(u, v);
	int dt = depth[u] - depth[v];
	li ans = 0;
	fto (i, 0, 16) if (isbit(dt, i)) {
		ans = max(ans, f[u][i]);
		u = root[u][i];
	}
	if (u == v) return ans;
	fdto (i, 16, 0) if (root[u][i] != root[v][i]) {
		ans = max({ans, f[u][i], f[v][i]});
		u = root[u][i];
		v = root[v][i];
	}
	return max({ans, f[u][0], f[v][0]});
}

int main() {
	#ifdef KITTENS
		freopen("main.inp", "r", stdin);
		freopen("main.out", "w", stdout);
	#endif
	ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);

	scanf("%d%d%d%d", &n, &m, &k, &query);

	int u, v, w;
	fto (i, 1, m) {
		scanf("%d%d%d", &u, &v, &w);
		ke[u].pb({v, w});
		ke[v].pb({u, w});
	}

	priority_queue<pair<li, int>, vector<pair<li, int>>, greater<pair<li, int>>> q;
	fto (i, 1, n) {
		if (i <= k) q.push({0, i});
		else d[i] = OO;
		p[i] = -1;
	}

	while (!q.empty()) {
		u = q.top().y;
		q.pop();
		fat (v, ke[u]) {
			li total = d[u] + v.y;
			if (d[v.x] > total) {
				d[v.x] = total;
				q.push({total, v.x});
			}
		}
	}

	fto (u, 1, n) fat (v, ke[u]) {
		edge.pb({d[u] + d[v.x] + v.y, {u, v.x}});
	}

	sort(all(edge));
	kruskal();
	dfs(1);

	while (query--) {
		scanf("%d%d", &u, &v);
		bug(lca(u, v));
	}

	#ifdef KITTENS
		cerr << 0.001*clock() << endl;
	#endif
	return 0;
}


#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace std;
using namespace __gnu_pbds;

#define fto(i, s, e) for(int i = (s); i <= (e); ++i)
#define fto1(i, s, e) for(int i = (s); i < (e); ++i)
#define fdto(i, s, e) for(int i = (s); i >= (e); --i)
#define fat(i, a) for(auto i : a)
#define fit(it, var) for(auto it = (var).begin(); it != (var).end(); ++it)
#define frit(it, var) for(auto it = (var).rbegin(); it != (var).rend(); ++it)

#define bc __builtin_popcountll
#define isbit(x, bit) (((x >> bit) & 1) != 0)
#define onbit(x, bit) (x | (1LL << bit))
#define offbit(x, bit) (x & ~(1LL << bit))
#define y1 ansdj
#define endl '\n'
#define _bug(...) bug(__func__, __LINE__, __VA_ARGS__)

#define li long long
#define cd complex<double>
#define ii pair<int, int>
#define ll pair<long, long>
#define x first
#define y second
#define pb push_back
#define sz(v) int((v).size())
#define all(v) (v).begin(), (v).end()

template<class T, class Cmp = less<T>> using oss = tree<T, null_type, Cmp, rb_tree_tag, tree_order_statistics_node_update>;

template<class T1, class T2> ostream& operator<<(ostream &os, pair<T1, T2> const &v) {
	return os << '(' << v.x << ", " << v.y << ')';
}

template<class T> ostream& operator<<(ostream &os, vector<T> const &v) {
	fto1 (i, 0, sz(v)) { os << v[i]; if (i < sz(v)-1) os << ' '; }
	return os;
}

template<class T> void buga(T const &v, int l, int r) { fto (i, l, r) { cout << v[i] << " \n"[i == r]; } }

template<class T> void bug(T const &v) { cout << v << endl; }
template<class T, class... Args> void bug(T const &v, Args const&... args) { cout << v << ' '; bug(args...); }

double const pi = acos(-1);
#define oo 1000000007
#define OO 1000000000000000003LL
int const maxn = 2e5+3;

int n, m, k, query;
int p[maxn], depth[maxn], pre[maxn], root[maxn][20];
li d[maxn], f[maxn][20];
vector<pair<int, li>> g[maxn];
vector<ii> ke[maxn];
vector<pair<li, ii>> edge;

int Par(int u) { return p[u] < 0 ? u : p[u] = Par(p[u]); }

bool Union(int u, int v) {
	u = Par(u); v = Par(v);
	if (u == v) return 0;
	if (p[u] > p[v]) swap(u, v);
	p[u] += p[v];
	p[v] = u;
	return 1;
}

void kruskal() {
	fat (e, edge) {
		ii node = e.y;
		if (Union(node.x, node.y)) {
			g[node.x].pb({node.y, e.x});
			g[node.y].pb({node.x, e.x});
		}
	}
}

void dfs(int u) {
	fto (i, 1, 16) {
		root[u][i] = root[root[u][i-1]][i-1];
		f[u][i] = max(f[u][i-1], f[root[u][i-1]][i-1]);
	}
	fat (v, g[u]) {
		if (v.x == root[u][0]) continue;
		root[v.x][0] = u;
		f[v.x][0] = v.y;
		depth[v.x] = depth[u] + 1;
		dfs(v.x);
	}
}

li lca(int u, int v) {
	if (depth[u] < depth[v]) swap(u, v);
	int dt = depth[u] - depth[v];
	li ans = 0;
	fto (i, 0, 16) if (isbit(dt, i)) {
		ans = max(ans, f[u][i]);
		u = root[u][i];
	}
	if (u == v) return ans;
	fdto (i, 16, 0) if (root[u][i] != root[v][i]) {
		ans = max({ans, f[u][i], f[v][i]});
		u = root[u][i];
		v = root[v][i];
	}
	return max({ans, f[u][0], f[v][0]});
}

int main() {
	#ifdef KITTENS
		freopen("main.inp", "r", stdin);
		freopen("main.out", "w", stdout);
	#endif
	ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);

	scanf("%d%d%d%d", &n, &m, &k, &query);

	int u, v, w;
	fto (i, 1, m) {
		scanf("%d%d%d", &u, &v, &w);
		ke[u].pb({v, w});
		ke[v].pb({u, w});
	}

	priority_queue<pair<li, int>, vector<pair<li, int>>, greater<pair<li, int>>> q;
	fto (i, 1, n) {
		if (i <= k) q.push({0, i});
		else d[i] = OO;
		p[i] = -1;
	}

	while (!q.empty()) {
		u = q.top().y;
		q.pop();
		fat (v, ke[u]) {
			li total = d[u] + v.y;
			if (d[v.x] > total) {
				d[v.x] = total;
				pre[v.x] = u;
				q.push({total, v.x});
			}
		}
	}

	fto (u, 1, n) fat (v, ke[u]) {
		if (v.x != pre[u]) edge.pb({d[u] + d[v.x] + v.y, {u, v.x}});
	}

	sort(all(edge));
	kruskal();
	dfs(1);

	while (query--) {
		scanf("%d%d", &u, &v);
		bug(lca(u, v));
	}

	#ifdef KITTENS
		cerr << 0.001*clock() << endl;
	#endif
	return 0;
}


#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace std;
using namespace __gnu_pbds;

#define fto(i, s, e) for(int i = (s); i <= (e); ++i)
#define fto1(i, s, e) for(int i = (s); i < (e); ++i)
#define fdto(i, s, e) for(int i = (s); i >= (e); --i)
#define fat(i, a) for(auto i : a)
#define fit(it, var) for(auto it = (var).begin(); it != (var).end(); ++it)
#define frit(it, var) for(auto it = (var).rbegin(); it != (var).rend(); ++it)

#define bc __builtin_popcountll
#define isbit(x, bit) (((x >> bit) & 1) != 0)
#define onbit(x, bit) (x | (1LL << bit))
#define offbit(x, bit) (x & ~(1LL << bit))
#define y1 ansdj
#define endl '\n'
#define _bug(...) bug(__func__, __LINE__, __VA_ARGS__)

#define ll long long
#define cd complex<double>
#define ii pair<int, int>
#define x first
#define y second
#define pb push_back
#define sz(v) int((v).size())
#define all(v) (v).begin(), (v).end()

template<class T, class Cmp = less<T>> using oss = tree<T, null_type, Cmp, rb_tree_tag, tree_order_statistics_node_update>;

template<class T1, class T2> ostream& operator<<(ostream &os, pair<T1, T2> const &v) {
	return os << '(' << v.x << ", " << v.y << ')';
}

template<class T> ostream& operator<<(ostream &os, vector<T> const &v) {
	fto1 (i, 0, sz(v)) { os << v[i]; if (i < sz(v)-1) os << ' '; }
	return os;
}

template<class T> void buga(T const &v, int l, int r) { fto (i, l, r) { cout << v[i] << " \n"[i == r]; } }

template<class T> void bug(T const &v) { cout << v << endl; }
template<class T, class... Args> void bug(T const &v, Args const&... args) { cout << v << ' '; bug(args...); }

double const pi = acos(-1);
#define oo 1000000007
#define OO 1000000000000000003LL
int const maxn = 2e5+3;

int n, m, k, query;
int d[maxn], p[maxn], depth[maxn];
int f[maxn][20], root[maxn][20];
vector<ii> ke[maxn], g[maxn];
vector<pair<int, ii>> edge;

int Par(int u) { return p[u] < 0 ? u : p[u] = Par(p[u]); }

bool Union(int u, int v) {
	u = Par(u); v = Par(v);
	if (u == v) return 0;
	if (p[u] > p[v]) swap(u, v);
	p[u] = p[v];
	p[v] = u;
	return 1;
}

void kruskal() {
	fat (e, edge) {
		ii node = e.y;
		if (Union(node.x, node.y)) {
			g[node.x].pb({node.y, e.x});
			g[node.y].pb({node.x, e.x});
		}
	}
}

void dfs(int u) {
	fto (i, 1, 16) {
		root[u][i] = root[root[u][i-1]][i-1];
		f[u][i] = max(f[u][i-1], f[root[u][i-1]][i-1]);
	}
	fat (v, g[u]) {
		if (v.x == root[u][0]) continue;
		root[v.x][0] = u;
		f[v.x][0] = v.y;
		depth[v.x] = depth[u] + 1;
		dfs(v.x);
	}
}

int lca(int u, int v) {
	if (depth[u] < depth[v]) swap(u, v);
	int dt = depth[u] - depth[v];
	int ans = 0;
	fto (i, 0, 16) if (isbit(dt, i)) {
		ans = max(ans, f[u][i]);
		u = root[u][i];
	}
	if (u == v) return ans;
	fdto (i, 16, 0) if (root[u][i] != root[v][i]) {
		ans = max({ans, f[u][i], f[v][i]});
		u = root[u][i];
		v = root[v][i];
	}
	return max({ans, f[u][0], f[v][0]});
}

int main() {
	#ifdef KITTENS
		freopen("main.inp", "r", stdin);
		freopen("main.out", "w", stdout);
	#endif
	ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);

	cin >> n >> m >> k >> query;

	int u, v, w;
	fto (i, 1, m) {
		cin >> u >> v >> w;
		ke[u].pb({v, w});
		ke[v].pb({u, w});
	}

	priority_queue<ii, vector<ii>, greater<ii>> q;
	fto (i, 1, n) {
		if (i <= k) q.push({0, i});
		else d[i] = oo;
		p[i] = -1;
	}

	while (!q.empty()) {
		u = q.top().y;
		q.pop();
		fat (v, ke[u]) {
			int total = v.y + d[u];
			if (d[v.x] > total) {
				d[v.x] = total;
				q.push({total, v.x});
			}
		}
	}

	fto (u, 1, n) fat (v, ke[u]) {
		edge.pb({d[u] + d[v.x] + v.y, {u, v.x}});
	}

	sort(all(edge));
	kruskal();
	dfs(1);

	while (query--) {
		cin >> u >> v;
		bug(lca(u, v));
	}

	#ifdef KITTENS
		cerr << 0.001*clock() << endl;
	#endif
	return 0;
}


#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace std;
using namespace __gnu_pbds;

#define fto(i, s, e) for(int i = (s); i <= (e); ++i)
#define fto1(i, s, e) for(int i = (s); i < (e); ++i)
#define fdto(i, s, e) for(int i = (s); i >= (e); --i)
#define fat(i, a) for(auto i : a)
#define fit(it, var) for(auto it = (var).begin(); it != (var).end(); ++it)
#define frit(it, var) for(auto it = (var).rbegin(); it != (var).rend(); ++it)

#define bc __builtin_popcountll
#define isbit(x, bit) (((x >> bit) & 1) != 0)
#define onbit(x, bit) (x | (1LL << bit))
#define offbit(x, bit) (x & ~(1LL << bit))
#define y1 ansdj
#define endl '\n'
#define _bug(...) bug(__func__, __LINE__, __VA_ARGS__)

#define ll long long
#define cd complex<double>
#define ii pair<int, int>
#define x first
#define y second
#define pb push_back
#define sz(v) int((v).size())
#define all(v) (v).begin(), (v).end()

template<class T, class Cmp = less<T>> using oss = tree<T, null_type, Cmp, rb_tree_tag, tree_order_statistics_node_update>;

template<class T1, class T2> ostream& operator<<(ostream &os, pair<T1, T2> const &v) {
	return os << '(' << v.x << ", " << v.y << ')';
}

template<class T> ostream& operator<<(ostream &os, vector<T> const &v) {
	fto1 (i, 0, sz(v)) { os << v[i]; if (i < sz(v)-1) os << ' '; }
	return os;
}

template<class T> void buga(T const &v, int l, int r) { fto (i, l, r) { cout << v[i] << " \n"[i == r]; } }

template<class T> void bug(T const &v) { cout << v << endl; }
template<class T, class... Args> void bug(T const &v, Args const&... args) { cout << v << ' '; bug(args...); }

double const pi = acos(-1);
#define oo 1000000007
#define OO 1000000000000000003LL
int const maxn = 2e5+3;

int n, m, k, query;
ll d[maxn], p[maxn], depth[maxn];
ll f[maxn][20], root[maxn][20];
vector<pair<ll, ll>> ke[maxn], g[maxn];
vector<pair<ll, ii>> edge;

int Par(int u) { return p[u] < 0 ? u : p[u] = Par(p[u]); }

bool Union(int u, int v) {
	u = Par(u); v = Par(v);
	if (u == v) return 0;
	if (p[u] > p[v]) swap(u, v);
	p[u] = p[v];
	p[v] = u;
	return 1;
}

void kruskal() {
	fat (e, edge) {
		ii node = e.y;
		if (Union(node.x, node.y)) {
			g[node.x].pb({node.y, e.x});
			g[node.y].pb({node.x, e.x});
		}
	}
}

void dfs(int u) {
	fto (i, 1, 16) {
		root[u][i] = root[root[u][i-1]][i-1];
		f[u][i] = max(f[u][i-1], f[root[u][i-1]][i-1]);
	}
	fat (v, g[u]) {
		if (v.x == root[u][0]) continue;
		root[v.x][0] = u;
		f[v.x][0] = v.y;
		depth[v.x] = depth[u] + 1;
		dfs(v.x);
	}
}

ll lca(int u, int v) {
	if (depth[u] < depth[v]) swap(u, v);
	int dt = depth[u] - depth[v];
	ll ans = 0;
	fto (i, 0, 16) if (isbit(dt, i)) {
		ans = max(ans, f[u][i]);
		u = root[u][i];
	}
	if (u == v) return ans;
	fdto (i, 16, 0) if (root[u][i] != root[v][i]) {
		ans = max({ans, f[u][i], f[v][i]});
		u = root[u][i];
		v = root[v][i];
	}
	return max({ans, f[u][0], f[v][0]});
}

int main() {
	#ifdef KITTENS
		freopen("main.inp", "r", stdin);
		freopen("main.out", "w", stdout);
	#endif
	ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);

	cin >> n >> m >> k >> query;

	int u, v, w;
	fto (i, 1, m) {
		cin >> u >> v >> w;
		ke[u].pb({v, w});
		ke[v].pb({u, w});
	}

	priority_queue<pair<ll, ll>, vector<pair<ll, ll>>, greater<pair<ll, ll>>> q;
	fto (i, 1, n) {
		if (i <= k) q.push({0, i});
		else d[i] = OO;
		p[i] = -1;
	}

	while (!q.empty()) {
		u = q.top().y;
		q.pop();
		fat (v, ke[u]) {
			ll total = v.y + d[u];
			if (d[v.x] > total) {
				d[v.x] = total;
				q.push({total, v.x});
			}
		}
	}

	fto (u, 1, n) fat (v, ke[u]) {
		edge.pb({d[u] + d[v.x] + v.y, {u, v.x}});
	}

	sort(all(edge));
	kruskal();
	dfs(1);

	while (query--) {
		cin >> u >> v;
		bug(lca(u, v));
	}

	#ifdef KITTENS
		cerr << 0.001*clock() << endl;
	#endif
	return 0;
}


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

#include <ext/rope>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_cxx;
using namespace __gnu_pbds;
template <typename T>
using ordered_set = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;

typedef long long ll;
typedef long double ld;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<ld,ld> pdd;
typedef complex<ld> pt;

const char nl = '\n';
const ll INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3f;
const ll MOD = 1e9+7;
const ld EPS = 1e-13;
mt19937 rng(chrono::high_resolution_clock::now().time_since_epoch().count());

struct Edge {
	int i; ll d;
	bool operator < (const Edge& o) const {
		return d > o.d;
	}
};

struct MSTE {
	int a, b; ll c;
	bool operator < (const MSTE& o) const {
		return c < o.c;
	}
};

const int N = 1e5+1;
ll dist[N];
vector<Edge> graph[N];
vector<Edge> adj[N];

int dsu[N];
int find(int i) {
	if(dsu[i]==0) return i;
	return dsu[i] = find(dsu[i]);
}
int link(int i, int j) {
	if(find(i)==find(j)) return 0;
	dsu[find(i)] = find(j);
	return 1;
}

const int L = 17;
int depth[N];
int anc[N][L];
ll maxv[N][L];

void build(int u, int p, ll c) {
	depth[u] = depth[p]+1;
	anc[u][0] = p;
	maxv[u][0] = c;
	for(int i=1;i<L;i++) {
		anc[u][i] = anc[anc[u][i-1]][i-1];
		maxv[u][i] = max(maxv[u][i-1], maxv[anc[u][i-1]][i-1]);
	}
	for(const Edge& e:adj[u]) {
		if(e.i == p) continue;
		build(e.i, u, e.d);
	}
}

ll query(int a, int b) {
	ll res = 0;
	if(depth[a] < depth[b]) swap(a,b);
	for(int j=L-1;j>=0;j--) {
		if(depth[a] - (1<<j) >= depth[b]) {
			res = max(res, maxv[a][j]);
			a = anc[a][j];
		}
	}
	if(a == b) return res;
	for(int j=L-1;j>=0;j--) {
		if(anc[a][j] == anc[b][j]) continue;
		res = max(res, maxv[a][j]);
		res = max(res, maxv[b][j]);
		a = anc[a][j];
		b = anc[b][j];
	}
	res = max(res, maxv[a][0]);
	res = max(res, maxv[b][0]);
	return res;
}

int main() {
	ios::sync_with_stdio(0); cin.tie(0);
	cout << fixed << setprecision(10);

	int n,m,k,q;
	cin>>n>>m>>k>>q;
	vector<MSTE> edges;
	for(int i=0;i<m;i++) {
		int a,b,c;
		cin>>a>>b>>c;
		graph[a].push_back({b,c});
		graph[b].push_back({a,c});
		edges.push_back({a,b,c});
	}

	priority_queue<Edge> dijk;
	for(int i=1;i<=k;i++) {
		dijk.push({i,0});
	}
	for(int i=k+1;i<=n;i++) {
		dist[i] = INFLL;
	}
	while(!dijk.empty()) {
		Edge cur = dijk.top();
		dijk.pop();
		if(cur.d > dist[cur.i]) continue;
		for(const Edge& e:graph[cur.i]) {
			if(e.d + cur.d < dist[e.i]) {
				dist[e.i] = e.d + cur.d;
				dijk.push({e.i, dist[e.i]});
			}
		}
	}

	for(MSTE& e : edges) {
		e.c += dist[e.a] + dist[e.b];
	}
	sort(edges.begin(), edges.end());

	for(const MSTE& e : edges) {
		if(link(e.a, e.b)) {
			adj[e.a].push_back({e.b,e.c});
			adj[e.b].push_back({e.a,e.c});
		}
	}

	build(1,0,0);

	for(int i=0;i<q;i++) {
		int a,b;
		cin>>a>>b;
		cout<<query(a,b)<<nl;
	}

	return 0;
}


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

#include <ext/rope>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_cxx;
using namespace __gnu_pbds;
template <typename T>
using ordered_set = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;

typedef long long ll;
typedef long double ld;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<ld,ld> pdd;
typedef complex<ld> pt;

const char nl = '\n';
const ll INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3f;
const ll MOD = 1e9+7;
const ld EPS = 1e-13;
mt19937 rng(chrono::high_resolution_clock::now().time_since_epoch().count());

struct Edge {
	int i; ll d;
	bool operator < (const Edge& o) const {
		return d > o.d;
	}
};

struct MSTE {
	int a, b; ll c;
	bool operator < (const MSTE& o) const {
		return c < o.c;
	}
};

const int N = 1e5+1;
ll dist[N];
vector<Edge> graph[N];
vector<Edge> adj[N];

int dsu[N];
int find(int i) {
	if(dsu[i]==0) return i;
	return dsu[i] = find(dsu[i]);
}
int link(int i, int j) {
	if(find(i)==find(j)) return 0;
	dsu[find(i)] = find(j);
	return 1;
}

const int L = 17;
int depth[N];
int anc[N][L];
ll maxv[N][L];

void build(int u, int p, ll c) {
	depth[u] = depth[p]+1;
	anc[u][0] = p;
	maxv[u][0] = c;
	for(int i=1;i<L;i++) {
		anc[u][i] = anc[anc[u][i-1]][i-1];
		maxv[u][i] = max(maxv[u][i-1], maxv[anc[u][i-1]][i-1]);
	}
	for(const Edge& e:adj[u]) {
		if(e.i == p) continue;
		build(e.i, u, e.d);
	}
}

ll query(int a, int b) {
	ll res = 0;
	if(depth[a] < depth[b]) swap(a,b);
	for(int j=L-1;j>0;j--) {
		if(depth[a] - (1<<j) >= depth[b]) {
			res = max(res, maxv[a][j]);
			a = anc[a][j];
		}
	}
	if(a == b) return res;
	for(int j=L-1;j>0;j--) {
		if(anc[a][j] == anc[b][j]) continue;
		res = max(res, maxv[a][j]);
		res = max(res, maxv[b][j]);
		a = anc[a][j];
		b = anc[b][j];
	}
	res = max(res, maxv[a][0]);
	res = max(res, maxv[b][0]);
	return res;
}

int main() {
	ios::sync_with_stdio(0); cin.tie(0);
	cout << fixed << setprecision(10);

	int n,m,k,q;
	cin>>n>>m>>k>>q;
	vector<MSTE> edges;
	for(int i=0;i<m;i++) {
		int a,b,c;
		cin>>a>>b>>c;
		graph[a].push_back({b,c});
		graph[b].push_back({a,c});
		edges.push_back({a,b,c});
	}

	priority_queue<Edge> dijk;
	for(int i=1;i<=k;i++) {
		dijk.push({i,0});
	}
	for(int i=k+1;i<=n;i++) {
		dist[i] = INFLL;
	}
	while(!dijk.empty()) {
		Edge cur = dijk.top();
		dijk.pop();
		if(cur.d > dist[cur.i]) continue;
		for(const Edge& e:graph[cur.i]) {
			if(e.d + cur.d < dist[e.i]) {
				dist[e.i] = e.d + cur.d;
				dijk.push({e.i, dist[e.i]});
			}
		}
	}

	for(MSTE& e : edges) {
		e.c += dist[e.a] + dist[e.b];
	}
	sort(edges.begin(), edges.end());

	for(const MSTE& e : edges) {
		if(link(e.a, e.b)) {
			adj[e.a].push_back({e.b,e.c});
			adj[e.b].push_back({e.a,e.c});
		}
	}
	build(1,0,0);

	for(int i=0;i<q;i++) {
		int a,b;
		cin>>a>>b;
		cout<<query(a,b)<<nl;
	}

	return 0;
}