#include <bits/stdc++.h>
using namespace std;
template <typename T, size_t N>
int SIZE(const T (&t)[N]) {
  return N;
}
template <typename T>
int SIZE(const T &t) {
  return t.size();
}
string to_string(const string s, int x1 = 0, int x2 = 1e9) {
  return '"' + ((x1 < s.size()) ? s.substr(x1, x2 - x1 + 1) : "") + '"';
}
string to_string(const char *s) { return to_string((string)s); }
string to_string(const bool b) { return (b ? "true" : "false"); }
string to_string(const char c) { return string({c}); }
template <size_t N>
string to_string(const bitset<N> &b, int x1 = 0, int x2 = 1e9) {
  string t = "";
  for (int __iii__ = min(x1, SIZE(b)), __jjj__ = min(x2, SIZE(b) - 1);
       __iii__ <= __jjj__; ++__iii__) {
    t += b[__iii__] + '0';
  }
  return '"' + t + '"';
}
template <typename A, typename... C>
string to_string(const A(&v), int x1 = 0, int x2 = 1e9, C... coords);
int l_v_l_v_l = 0, t_a_b_s = 0;
template <typename A, typename B>
string to_string(const pair<A, B> &p) {
  l_v_l_v_l++;
  string res = "(" + to_string(p.first) + ", " + to_string(p.second) + ")";
  l_v_l_v_l--;
  return res;
}
template <typename A, typename... C>
string to_string(const A(&v), int x1, int x2, C... coords) {
  int rnk = rank<A>::value;
  string tab(t_a_b_s, ' ');
  string res = "";
  bool first = true;
  if (l_v_l_v_l == 0) res += '\n';
  res += tab + "[";
  x1 = min(x1, SIZE(v)), x2 = min(x2, SIZE(v));
  auto l = begin(v);
  advance(l, x1);
  auto r = l;
  advance(r, (x2 - x1) + (x2 < SIZE(v)));
  for (auto e = l; e != r; e = next(e)) {
    if (!first) {
      res += ", ";
    }
    first = false;
    l_v_l_v_l++;
    if (e != l) {
      if (rnk > 1) {
        res += '\n';
        t_a_b_s = l_v_l_v_l;
      };
    } else {
      t_a_b_s = 0;
    }
    res += to_string(*e, coords...);
    l_v_l_v_l--;
  }
  res += "]";
  if (l_v_l_v_l == 0) res += '\n';
  return res;
}
void dbgm() { ; }
template <typename Heads, typename... Tails>
void dbgm(Heads H, Tails... T) {
  cout << to_string(H) << " | ";
  dbgm(T...);
}
const int N = 105;
const int B = 100005;
int d[N][N], gain[B];
void floyd(int n) {
  for (int i = 0; i < n; i++) d[i][i] = 0;
  for (int k = 0; k < n; k++)
    for (int i = 0; i < n; i++)
      for (int j = 0; j < n; j++) d[i][j] = min(d[i][j], d[i][k] + d[j][k]);
}
struct ship {
  int x, a, f, p;
};
struct base {
  int x, d, g;
};
struct node {
  vector<base> bases;
  vector<int> maxs;
  void add(base base) { bases.push_back(base); }
  void prepare() {
    sort(bases.begin(), bases.end(),
         [](base a, base b) -> bool { return a.d < b.d; });
    maxs.push_back(-1);
    for (int i = 0; i < ((int)bases.size()); i++) {
      maxs.push_back(max(maxs.back(), bases[i].g));
    }
  }
  int bin(int s) {
    int izq = 0, der = ((int)bases.size()) - 1;
    int res = ((int)bases.size());
    while (izq <= der) {
      int med = (izq + der) / 2;
      if (bases[med].d > s)
        res = med, der = med - 1;
      else
        izq = med + 1;
    }
    if (res < ((int)bases.size())) assert(bases[res].d > s);
    return res;
  }
  int query(int strength) {
    int p = bin(strength);
    return maxs[p];
  }
};
const long long INF = 1e15;
struct Dinic {
  int nodes, src, dst;
  vector<int> dist, q, work;
  struct edge {
    int to, rev;
    long long f, cap;
  };
  vector<vector<edge>> g;
  Dinic(int x) : nodes(x), g(x), dist(x), q(x), work(x) {}
  void add_edge(int s, int t, long long cap) {
    g[s].push_back((edge){t, ((int)g[t].size()), 0, cap});
    g[t].push_back((edge){s, ((int)g[s].size()) - 1, 0, 0});
  }
  bool dinic_bfs() {
    fill(dist.begin(), dist.end(), -1);
    dist[src] = 0;
    int qt = 0;
    q[qt++] = src;
    for (int qh = 0; qh < qt; qh++) {
      int u = q[qh];
      for (int i = 0; i < ((int)g[u].size()); i++) {
        edge &e = g[u][i];
        int v = g[u][i].to;
        if (dist[v] < 0 && e.f < e.cap) dist[v] = dist[u] + 1, q[qt++] = v;
      }
    }
    return dist[dst] >= 0;
  }
  long long dinic_dfs(int u, long long f) {
    if (u == dst) return f;
    for (int &i = work[u]; i < ((int)g[u].size()); i++) {
      edge &e = g[u][i];
      if (e.cap <= e.f) continue;
      int v = e.to;
      if (dist[v] == dist[u] + 1) {
        long long df = dinic_dfs(v, min(f, e.cap - e.f));
        if (df > 0) {
          e.f += df;
          g[v][e.rev].f -= df;
          return df;
        }
      }
    }
    return 0;
  }
  long long max_flow(int _src, int _dst) {
    src = _src;
    dst = _dst;
    long long result = 0;
    while (dinic_bfs()) {
      fill(work.begin(), work.end(), 0);
      while (long long delta = dinic_dfs(src, INF)) result += delta;
    }
    return result;
  }
};
int main() {
  int n, m, s, b, k;
  cin >> n >> m;
  for (int i = 0; i < n; i++)
    for (int j = 0; j < n; j++) d[i][j] = 1000;
  for (int i = 0; i < m; i++) {
    int u, v;
    cin >> u >> v;
    u--, v--;
    d[u][v] = d[v][u] = 1;
  }
  floyd(n);
  cin >> s >> b >> k;
  vector<ship> ships;
  vector<node> nodes(n);
  for (int i = 0; i < s; i++) {
    int x, a, f, p;
    cin >> x >> a >> f >> p;
    x--;
    ships.push_back({x, a, min(200, f), p});
  }
  for (int i = 0; i < b; i++) {
    int x, d, g;
    cin >> x >> d >> g;
    x--;
    nodes[x].add({x, d, g});
  }
  for (int i = 0; i < n; i++) nodes[i].prepare();
  memset(gain, -1, sizeof(gain));
  for (int i = 0; i < s; i++) {
    for (int j = 0; j < n; j++)
      if (d[ships[i].x][j] <= ships[i].f) {
        gain[i] = max(gain[i], nodes[j].query(ships[i].a));
      }
  }
  Dinic d(s + 2);
  long long tot = 0;
  for (int i = 0; i < s; i++) {
    if (gain[i] == -1) {
      d.add_edge(i, s + 1, 1e18);
    } else {
      long long g = gain[i] - ships[i].p;
      if (g > 0)
        d.add_edge(s, i, g), tot += g;
      else
        d.add_edge(i, s + 1, -g);
    }
  }
  for (int i = 0; i < k; i++) {
    int s, t;
    cin >> s >> t;
    s--, t--;
    d.add_edge(s, t, INF);
  }
  cout << tot - d.max_flow(s, s + 1) << '\n';
  return 0;
}
