#include <iostream>
#include <vector>
#include <cassert>
#include <algorithm>
#include <cstdio>
#include <tuple>
#include <cstring>
#include <set>
#include <valarray>
#include <queue>
#include <algorithm>

using namespace std;
typedef long long ll;

template<int V>
struct Dijkstra {
//    using T = int;
    typedef int T;
//    using P = pair<T, int>;
    typedef pair<T, int> P;
    static const T INF = 1<<28;
    vector<P> g[V];
    void add(int from, int to, T dist) {
        g[from].push_back(P(dist, to));
    }
    T res[V];
    void exec(int s) {
        fill_n(res, V, INF);
        priority_queue<P, vector<P>, greater<P>> q;
        q.push(P(0, s));
        while (!q.empty()) {
            P p = q.top(); q.pop();
            if (res[p.second] != INF) continue;
            res[p.second] = p.first;
            for (P e: g[p.second]) {
                q.push(P(e.first+p.first, e.second));
            }
        }
        return;
    }
};

struct LCNode {
    typedef LCNode* NP;
    typedef int D;
    static const int INF = 1LL<<25;
    static LCNode last_d;
    static NP last;
    NP p, l, r;
    int sz;
    D id, v, mi;
    bool rev;
    LCNode(D v) :p(nullptr), l(last), r(last), sz(1), v(v), mi(v) {}
    LCNode() : l(nullptr), r(nullptr), sz(0) {}
    inline int pos() {
        if (p) {
            if (p->l == this) return -1;
            if (p->r == this) return 1;
        }
        return 0;
    }
    void rot() {
        NP qq = p->p;
        int pps = p->pos();
        if (p->l == this) {
            p->l = r; r->p = p;
            r = p; p->p = this;
        } else {
            p->r = l; l->p = p;
            l = p; p->p = this;
        }
        p->update(); update();
        p = qq;
        if (!pps) return;
        if (pps == -1) {
            qq->l = this;
        } else {
            qq->r = this;
        }
        qq->update();
    }
    void splay() {
        assert(this != last);
        supush();
        int ps;
        while ((ps = pos())) {
            int pps = p->pos();
            if (!pps) {
                rot();
            } else if (ps == pps) {
                p->rot(); rot();
            } else {
                rot(); rot();
            }
        }
    }
    void expose() {
        assert(this != last);
        NP u = this, ur = last;
        do {
            u->splay();
            u->r = ur;
            u->update();
            ur = u;
        } while ((u = u->p));
        splay();
    }
    void supush() {
        if (pos()) {
            p->supush();
        }
        push();
    }
    void push() {
        int lsz = l->sz, rsz = r->sz;
        if (rev) {
            if (lsz) {
                l->revdata();
            }
            if (rsz) {
                r->revdata();
            }
            rev = false;
        }
    }
    void revdata() {
        assert(this != last);
        swap(l, r);
        rev ^= true;
    }
    NP update() {
        assert(this != last);
        mi = v;
        if (l->sz) {
            mi = min(mi, l->mi);
        }
        if (r->sz) {
            mi = min(mi, r->mi);
        }
        sz = 1+l->sz+r->sz;
        return this;
    }

    NP root() {
        expose();
        NP u = this;
        while (u->l != last) {
            u = u->l;
        }
        u->splay();
        return u;
    }

    void evert() {
        expose();
        revdata();
    }

    void link(NP r) {
        assert(this != r);
        expose();
        r->expose();
        assert(l == last);
        p = r;
    }

    D get() {
        expose();
        return mi;
    }
};

LCNode LCNode::last_d = LCNode();
LCNode::NP LCNode::last = &last_d;

template <int N>
struct UnionFind {
    int ig[N];
    vector<int> gi[N];
    int dc;
    void init(int n = N) {
        for (int i = 0; i < n; ++i) {
            ig[i] = i;
            gi[i] = {i};
        }
        dc = 0;
    }
 
    void merge(int a, int b) {
        if (same(a, b)) return;
        dc++;
        int x = ig[a], y = ig[b];
        if (gi[x].size() < gi[y].size()) swap(x, y);
        for (int j: gi[y]) {
            ig[j] = x;
        }
        gi[x].insert(gi[x].end(), gi[y].begin(), gi[y].end());
        gi[y].clear();
    }
 
    bool same(int a, int b) {
        return ig[a] == ig[b];
    }
};
typedef pair<int, int> P;

const int MN = 100100;
const int MM = 200200;

LCNode tr[MN];
Dijkstra<MN> dijk;
UnionFind<MN> uf;
int a[MM], b[MM], c[MM];
P e[MM];
int main() {
    uf.init();
    int n, m, k, q;
    scanf("%d %d %d %d", &n, &m, &k, &q);
    for (int i = 0; i < m; i++) {
        scanf("%d %d %d", a+i, b+i, c+i); a[i]--; b[i]--;
        dijk.add(a[i], b[i], c[i]);
        dijk.add(b[i], a[i], c[i]);
    }
    for (int i = 0; i < k; i++) {
        int d;
        scanf("%d", &d); d--;
        dijk.add(MN-1, d, 0);
    }
    dijk.exec(MN-1);
    for (int i = 0; i < n; i++) {
        tr[i] = LCNode(dijk.res[i]);
    }
    for (int i = 0; i < m; i++) {
        e[i] = P(min(dijk.res[a[i]], dijk.res[b[i]]), i);
    }
    sort(e, e+m, greater<P>());
    for (int i = 0; i < m; i++) {
        int j = e[i].second;
        int aa = a[j], bb = b[j];
        if (uf.same(aa, bb)) continue;
        uf.merge(aa, bb);
        tr[aa].evert();
        tr[aa].link(tr+bb);
    }
    for (int i = 0; i < q; i++) {
        int x, y;
        scanf("%d %d", &x, &y); x--; y--;
        tr[x].evert();
        printf("%d\n", tr[y].get());
    }
    return 0;
}

Measured memory_bytes: 29932