#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 1e9 + 20;
int n;
int m[2];
int qnum;
struct node {
node* c[2];
node* p;
bool flip;
int idx;
int val;
node* max_node;
int d() {
assert(p);
return p->c[1] == this;
}
bool r() {
return !(p && p->c[d()] == this);
}
void do_flip() {
flip = !flip;
}
void propagate() {
if (flip) {
flip = false;
swap(c[0], c[1]);
for (int i = 0; i < 2; i++) {
if (c[i]) c[i]->do_flip();
}
}
}
void upd() {
max_node = this;
for (int i = 0; i < 2; i++) {
if (c[i] && c[i]->max_node->val > max_node->val) {
max_node = c[i]->max_node;
}
}
}
void propagate_all() {
if (!r()) p->propagate_all();
propagate();
}
void rot() {
int x = d();
node* pa = p;
node* ch = c[!x];
if (!pa->r()) pa->p->c[pa->d()] = this;
p = pa->p;
pa->c[x] = ch;
if (ch) ch->p = pa;
c[!x] = pa;
pa->p = this;
pa->upd();
upd();
}
void splay() {
propagate_all();
while (!r()) {
if (!p->r()) {
if (p->d() == d()) p->rot();
else rot();
}
rot();
}
}
void expose() {
splay();
while (p) {
p->splay();
p->c[1] = this;
rot();
}
c[1] = NULL;
upd();
assert(r());
}
void make_root() {
expose();
assert(r());
do_flip();
}
void cut() {
expose();
assert(c[1] == NULL);
assert(!flip);
assert(c[0]);
c[0]->p = NULL;
c[0] = NULL;
upd();
}
void link(node* v) {
assert(get_root() != v->get_root());
make_root();
p = v;
}
node* get_root() {
expose();
node* v = this;
while (true) {
v->propagate();
if (!v->c[0]) break;
v = v->c[0];
}
v->expose();
return v;
}
friend node* get_max(node* a, node* b) {
assert(a && b);
a->make_root();
b->expose();
assert(b->max_node);
return b->max_node;
}
};
struct edge {
int a, b;
int k;
friend istream& operator >> (istream& i, edge& e) {
cin >> e.a >> e.b >> e.k;
e.a--; e.b--;
return i;
}
bool operator < (const edge& o) const {
return k < o.k;
}
};
vector<edge> trees[2];
vector<edge> tree_mst[2];
vector<int> uf;
void reset_uf() {
fill(uf.begin(), uf.end(), -1);
}
int getpar(int a) {
return uf[a] < 0 ? a : (uf[a] = getpar(uf[a]));
}
bool unite(int a, int b) {
a = getpar(a);
b = getpar(b);
if (a == b) return false;
if (-uf[a] < -uf[b]) swap(a, b);
uf[a] += uf[b];
uf[b] = a;
return true;
}
void solve_mst(vector<edge>& edges, vector<edge>& mst) {
sort(edges.begin(), edges.end());
reset_uf();
for (int e = 0; e < int(edges.size()); e++) {
if (unite(edges[e].a, edges[e].b)) {
mst.push_back(edges[e]);
}
}
assert(int(mst.size()) == n-1);
}
vector<node> vert_nodes;
vector<node> edge_nodes;
int main() {
ios::sync_with_stdio(0), cin.tie(0);
cin >> n >> m[0] >> m[1] >> qnum;
uf.resize(n);
for (int z = 0; z < 2; z++) {
trees[z].resize(m[z]);
for (int e = 0; e < m[z]; e++) {
cin >> trees[z][e];
}
solve_mst(trees[z], tree_mst[z]);
}
vert_nodes.resize(n);
for (int i = 0; i < n; i++) {
vert_nodes[i].val = -INF;
vert_nodes[i].idx = -1;
vert_nodes[i].upd();
}
edge_nodes.resize(n-1);
for (int e = 0; e < n-1; e++) {
edge_nodes[e].val = tree_mst[0][e].k;
edge_nodes[e].idx = e;
edge_nodes[e].upd();
}
ll cur = 0;
for (int e = 0; e < n-1; e++) {
int a = tree_mst[0][e].a;
int b = tree_mst[0][e].b;
cur += tree_mst[0][e].k;
vert_nodes[a].link(&edge_nodes[e]);
vert_nodes[b].link(&edge_nodes[e]);
}
vector<int> ntr;
ntr.reserve(n-1);
for (int e = 0; e < n-1; e++) {
int a = tree_mst[1][e].a;
int b = tree_mst[1][e].b;
node* max_path = get_max(&vert_nodes[a], &vert_nodes[b]);
if (max_path->val == -INF) continue;
int idx = max_path->idx;
max_path->make_root();
vert_nodes[tree_mst[0][idx].a].cut();
vert_nodes[tree_mst[0][idx].b].cut();
vert_nodes[a].link(&vert_nodes[b]);
ntr.push_back(tree_mst[1][e].k - max_path->val);
}
sort(ntr.begin(), ntr.end());
vector<pair<int, int> > queries(qnum);
for (int i = 0; i < qnum; i++) {
int t;
cin >> t;
queries[i] = make_pair(t, i);
}
sort(queries.begin(), queries.end());
vector<ll> answers(qnum);
for (int i = 0, j = 0; i < qnum; i++) {
int t = queries[i].first;
int idx = queries[i].second;
while (j < int(ntr.size()) && ntr[j] <= 2*t) {
cur += ntr[j];
j++;
}
answers[idx] = cur + ll(t) * (-j + (n-1-j));
}
for (int i = 0; i < qnum; i++) {
cout << answers[i] << '\n';
}
}