#include<bits/stdc++.h>

#define REP(i,s,n) for(int i=s;i<n;i++)
#define rep(i,n) REP(i,0,n)

using namespace std;
/*
typedef long long ll;
typedef pair<ll,int> ii;
 
struct Edge{
  int to; ll cap; ll cost; int rev;
  Edge(int to=0,int cap=0,ll cost=0,int rev=0):to(to),cap(cap),cost(cost),rev(rev){}
};
 
const int MAX_V = 1100; const ll IINF = LLONG_MAX;
int V;
vector<Edge> G[MAX_V];
ll h[MAX_V],dist[MAX_V]; int prevv[MAX_V],preve[MAX_V];
 
inline void add_edge(int from,int to,int cap,ll cost){
  G[from].push_back(Edge(to,cap,cost,G[to].size()));
  G[to].push_back(Edge(from,0,-cost,G[from].size()-1));
}
 

ll min_cost_flow(int s,int t){
  ll res = 0;
  while(1){
    fill(dist,dist+V,IINF);
    dist[s] = 0;
    bool update = true;
    while( update ){
      update = false;
      rep(v,V){
        if( dist[v] == IINF ) continue;
        rep(i,(int)G[v].size()){
          Edge &e = G[v][i];
          if( e.cap > 0LL && 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] == IINF ) break;
 
    ll d = IINF;
    for(int v=t;v!=s;v=prevv[v]) d = min(d,G[prevv[v]][preve[v]].cap);
    if( d == 0LL ) break;

    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;
}
*/
typedef long long ll;
typedef pair<ll,int> ii;


struct Edge{
  int to; ll cap,cost; int rev;
  Edge(int to=0,ll cap=0,ll cost=0,int rev=0):to(to),cap(cap),cost(cost),rev(rev){}
};

const int MAX_V = 1100; ll IINF = LLONG_MAX;
int V;
vector<Edge> G[MAX_V];
ll h[MAX_V],dist[MAX_V]; int prevv[MAX_V],preve[MAX_V];

inline void add_edge(int from,int to,ll cap,ll cost){
  G[from].push_back(Edge(to,cap,cost,G[to].size()));
  G[to].push_back(Edge(from,0,-cost,G[from].size()-1));
}

ll min_cost_flow(int s,int t){
  ll res = 0;
  fill(h,h+V,0);
  while(1){
    priority_queue<ii,vector<ii>,greater<ii> > Q;
    fill(dist,dist+V,IINF);
    dist[s] = 0;
    Q.push(ii(0,s));
    while(!Q.empty()){
      ii p = Q.top(); Q.pop();
      int v = p.second;
      if( dist[v] < p.first ) 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 + 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;
          Q.push(ii(dist[e.to],e.to));
        }
      }
    }
    //if( dist[t] == IINF ) break;
    rep(v,V) h[v] += dist[v];
    if( h[t] >= 0LL ) break;
    ll d = IINF;
    for(int v=t;v!=s;v=prevv[v]) d = min(d,G[prevv[v]][preve[v]].cap);
    res += d * h[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;
}


int N,M;

int main(){
  cin >> N >> M;

  int source = N+M;
  int sink = source + 1;
  V = sink + 1;
  rep(i,N) add_edge(source,i,1,0);
  rep(i,M) add_edge(N+i,sink,1,0);
  
  set<ii> S[2];
  int L,a,b;
  cin >> L;
  rep(i,L) { cin >> a >> b; S[0].insert(ii(a,b)); }
  cin >> L;
  rep(i,L) { cin >> a >> b; S[1].insert(ii(a,b)); }
  cin >> L;
  rep(i,L) {
    cin >> a >> b;
    if( S[0].count(ii(b,a)) ) add_edge(b,N+a,1,-1000000000LL);
    if( S[1].count(ii(b,a)) ) add_edge(b,N+a,1,-1000000LL);
  }
  cin >> L;
  rep(i,L) {
    cin >> a >> b;
    if( S[0].count(ii(b,a)) ) add_edge(b,N+a,1,-1000000LL);
    if( S[1].count(ii(b,a)) ) add_edge(b,N+a,1,-1000LL);
  }
  ll res = -1 * min_cost_flow(source,sink);
    cout << res/1000000000LL << " "
       << res/1000000LL%1000LL << " "
       << res/1000LL%1000LL << endl;
  return 0;
}


Measured memory_bytes: 1588