#include <bits/stdc++.h>
using ll = long long;
const ll LINF = 1e13;
using namespace std;
namespace ProconLib {
template <typename cost_t = long long, bool hasNegativeCost = false,
          cost_t INF = LINF>
class Flow {
 public:
  struct Edge {
    int to;
    cost_t cap, rev;
    cost_t cost;
  };
  using Edges = vector<Edge>;
  using Graph = vector<Edges>;

 private:
  int N;
  Graph g;
  vector<int> level;
  vector<int> iter;
  void bfs(int s);
  cost_t dfs(int v, int t, cost_t f);

 public:
  Flow(int N) : N(N), g(N){};
  void addEdge(int from, int to, cost_t cap);
  void addEdge(int from, int to, cost_t cap, cost_t cost);
  cost_t maxFlow(int s, int t);
  cost_t minCostFlow(int s, int t, cost_t f);
};
template <typename cost_t, bool hasNegativeCost, cost_t INF>
void Flow<cost_t, hasNegativeCost, INF>::addEdge(int from, int to, cost_t cap) {
  g[from].push_back({to, cap, int(g[to].size()), 0});
  g[to].push_back({from, cost_t(0), int(g[from].size()) - 1, 0});
}
template <typename cost_t, bool hasNegativeCost, cost_t INF>
void Flow<cost_t, hasNegativeCost, INF>::addEdge(int from, int to, cost_t cap,
                                                 cost_t cost) {
  g[from].push_back({to, cap, int(g[to].size()), cost});
  g[to].push_back({from, cost_t(0), int(g[from].size()) - 1, -cost});
}
template <typename cost_t, bool hasNegativeCost, cost_t INF>
cost_t Flow<cost_t, hasNegativeCost, INF>::maxFlow(int s, int t) {
  cost_t flow = 0;
  while (true) {
    bfs(s);
    if (level[t] < 0) return flow;
    iter.assign(N, 0);
    cost_t f;
    while ((f = dfs(s, t, INF)) > 0) {
      flow += f;
    }
  }
}
template <typename cost_t, bool hasNegativeCost, cost_t INF>
void Flow<cost_t, hasNegativeCost, INF>::bfs(int s) {
  level.assign(N, -1);
  queue<int> que;
  level[s] = 0;
  que.push(s);
  while (!que.empty()) {
    int v = que.front();
    que.pop();
    for (int i = 0; i < g[v].size(); i++) {
      Edge& e = g[v][i];
      if (e.cap > 0 && level[e.to] < 0) {
        level[e.to] = level[v] + 1;
        que.push(e.to);
      }
    }
  }
}
template <typename cost_t, bool hasNegativeCost, cost_t INF>
cost_t Flow<cost_t, hasNegativeCost, INF>::dfs(int v, int t, cost_t f) {
  if (v == t) return f;
  for (int& i = iter[v]; i < g[v].size(); i++) {
    Edge& e = g[v][i];
    if (e.cap > 0 && level[v] < level[e.to]) {
      cost_t d = dfs(e.to, t, min(f, e.cap));
      if (d > 0) {
        e.cap -= d;
        g[e.to][e.rev].cap += d;
        return d;
      }
    }
  }
  return 0;
}
template <typename cost_t, bool hasNegativeCost, cost_t INF>
cost_t Flow<cost_t, hasNegativeCost, INF>::minCostFlow(int s, int t, cost_t f) {
  using P = pair<cost_t, int>;
  cost_t res = 0;
  vector<cost_t> h(N, 0);
  vector<int> used(N), preve(N), prevv(N);
  vector<cost_t> dist(N);
  while (f > 0) {
    fill(dist.begin(), dist.end(), INF);
    dist[s] = 0;
    if (!hasNegativeCost) {
      fill(used.begin(), used.end(), 0);
      priority_queue<P, vector<P>, greater<P>> que;
      que.push(make_pair(cost_t(0), s));
      while (!que.empty()) {
        P p = que.top();
        que.pop();
        int v = p.second;
        if (used[v]) continue;
        used[v] = true;
        for (int i = 0; i < g[v].size(); i++) {
          Edge& e = g[v][i];
          if (e.cap > 0 && dist[e.to] > dist[v] + e.cost + h[v] - h[e.to]) {
            dist[e.to] = dist[v] + e.cost + h[v] - h[e.to];
            prevv[e.to] = v;
            preve[e.to] = i;
            que.push(make_pair(dist[e.to], e.to));
          }
        }
      }
    } else {
      bool update = true;
      while (update) {
        update = false;
        for (int v = 0; v < N; v++) {
          if (dist[v] == INF) continue;
          for (int i = 0; i < g[v].size(); i++) {
            Edge& e = g[v][i];
            if (e.cap > 0 && dist[e.to] > dist[v] + e.cost) {
              dist[e.to] = dist[v] + e.cost;
              prevv[e.to] = v;
              preve[e.to] = i;
              update = true;
            }
          }
        }
      }
    }
    if (dist[t] == INF) {
      return -1;
    }
    if (!hasNegativeCost) {
      for (int v = 0; v < N; v++) h[v] += dist[v];
    }
    cost_t d = f;
    for (int v = t; v != s; v = prevv[v]) {
      d = min(d, g[prevv[v]][preve[v]].cap);
    }
    f -= d;
    if (!hasNegativeCost) {
      res += d * h[t];
    } else {
      res += d * dist[t];
    }
    for (int v = t; v != s; v = prevv[v]) {
      Edge& e = g[prevv[v]][preve[v]];
      e.cap -= d;
      g[v][e.rev].cap += d;
    }
  }
  return res;
}
}  // namespace ProconLib
struct Spaceship {
  int x, a, f, p;
};
struct Base {
  int x, d, g;
};
using namespace ProconLib;
using vvi = vector<vector<int>>;
void dfs(int v, vvi& g, vector<int>& used, vector<int>& vs) {
  used[v] = true;
  vs.push_back(v);
  for (auto to : g[v]) {
    if (used[to]) continue;
    dfs(to, g, used, vs);
  }
}
int main() {
  int n, m;
  cin >> n >> m;
  vector<vector<int>> dist(n, vector<int>(n, 1e9 + 5));
  for (int i = 0; i < m; i++) {
    int u, v;
    cin >> u >> v;
    u--, v--;
    dist[u][v] = 1;
    dist[v][u] = 1;
  }
  for (int i = 0; i < n; i++) dist[i][i] = 0;
  int s, b, k;
  cin >> s >> b >> k;
  vector<Spaceship> ship(s);
  for (int i = 0; i < s; i++) {
    cin >> ship[i].x >> ship[i].a >> ship[i].f >> ship[i].p, ship[i].x--;
  }
  vector<Base> base(b);
  for (int i = 0; i < b; i++) {
    cin >> base[i].x >> base[i].d >> base[i].g;
    base[i].x--;
  }
  vvi sg(s);
  for (int i = 0; i < k; i++) {
    int s1, s2;
    cin >> s1 >> s2;
    s1--, s2--;
    sg[s1].push_back(s2);
  }
  for (int k = 0; k < n; k++) {
    for (int i = 0; i < n; i++) {
      for (int j = 0; j < n; j++) {
        dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);
      }
    }
  }
  vector<ll> profit(s, -LINF);
  vector<vector<int>> bids(n);
  for (int i = 0; i < b; i++) {
    bids[base[i].x].push_back(i);
  }
  auto cmp = [&](int lhs, int rhs) { return base[lhs].d < base[rhs].d; };
  for (int i = 0; i < n; i++) sort(bids[i].begin(), bids[i].end(), cmp);
  vector<vector<int>> accMax(n);
  for (int i = 0; i < n; i++) {
    accMax[i].resize(bids[i].size() + 1);
    for (int j = 0; j < bids[i].size(); j++) {
      accMax[i][j + 1] = max(accMax[i][j], base[bids[i][j]].g);
    }
  }
  for (int i = 0; i < s; i++) {
    int x = ship[i].x;
    for (int v = 0; v < n; v++) {
      if (dist[x][v] <= ship[i].f) {
        int lb = -1, ub = bids[v].size();
        while (ub - lb > 1) {
          int mid = (lb + ub) / 2;
          if (base[bids[v][mid]].d <= ship[i].a)
            lb = mid;
          else
            ub = mid;
        }
        ll sc = accMax[v][ub] - ship[i].p;
        if (ub > 0) profit[i] = max(profit[i], sc);
      }
    }
  }
  auto doFlow = [&](const vvi& graph, const vector<ll>& mpPro) {
    int n = graph.size();
    const int S = n;
    const int T = n + 1;
    Flow<ll> flow(n + 2);
    ll sum = 0;
    for (int i = 0; i < n; i++) {
      if (mpPro[i] > 0) {
        sum += mpPro[i];
        flow.addEdge(S, i, mpPro[i]);
        flow.addEdge(i, T, 0);
      } else {
        flow.addEdge(S, i, 0);
        flow.addEdge(i, T, -mpPro[i]);
      }
    }
    for (int i = 0; i < n; i++) {
      for (auto to : graph[i]) {
        flow.addEdge(i, to, LINF);
      }
    }
    return sum - flow.maxFlow(S, T);
  };
  vvi undirSG(s);
  for (int i = 0; i < s; i++) {
    for (auto to : sg[i]) {
      undirSG[i].push_back(to);
      undirSG[to].push_back(i);
    }
  }
  ll res = 0;
  vector<int> used(s);
  for (int i = 0; i < s; i++) {
    if (!used[i]) {
      vector<int> vs;
      dfs(i, undirSG, used, vs);
      if (vs.size() == 1) {
        if (profit[i] > 0) res += profit[i];
        continue;
      }
      map<int, int> mp;
      int id = 0;
      for (auto v : vs) {
        mp[v] = id++;
      }
      vvi mapG(id);
      vector<ll> mpPro(id);
      for (auto v : vs) {
        mpPro[mp[v]] = profit[v];
        for (auto to : sg[v]) {
          mapG[mp[v]].push_back(mp[to]);
        }
      }
      res += doFlow(mapG, mpPro);
    }
  }
  cout << res << endl;
  return 0;
}
