#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
#define CLR(x,a) memset(x,a,sizeof(x))

using namespace std;

const int N=1e5+10,K=5,M=5e5+10;
int ans,bns,a[N],mm,n,m,dptree[N][1<<K],g[N][1<<K],st[N],endSt,p[N];
bool vis[N][1<<K];
queue <int> que;
struct TT
{
    int vid,next;
}e[2*M];

void Insert(int a,int b)
{
//    printf("%d %d\n",a,b);
    mm++;
    e[mm].vid=b;
    e[mm].next=p[a];
    p[a]=mm;
}

int input()
{
   /*
    *    ?入，并且返回指定集合元素个数K
    *    因?有?候元素个数需要通??入数据?理出来，所以?独?个?入函数。
    */
    int x,y,z;
    scanf("%d%d%d%d",&n,&x,&y,&z);
    for (int i=1; i<=n; i++) a[i]=i+3;
    int t;
    bns=n+10;
    for (int i=1; i<=x; i++) scanf("%d",&t),a[t]=1,bns=min(bns,t);
    for (int i=1; i<=y; i++) scanf("%d",&t),a[t]=2,bns=min(bns,t);
    for (int i=1; i<=z; i++) scanf("%d",&t),a[t]=3,bns=min(bns,t);
    mm=-1;
    for (int i=1; i<=n+3; i++) p[i]=-1;
    scanf("%d",&m);
    for (int i=1; i<=m; i++)
    {
        scanf("%d%d",&x,&y);
        Insert(a[x],a[y]),Insert(a[y],a[x]);
    }
/*
 *  Steiner Tree：求，使得指定K个点?通的生成?的最小???
 *  st[i] 表示?点i的???，如果i是指定集合内第m(0<=m<K)个点，?st[i]=1<<m
 *  endSt=1<<K
 *  dptree[i][state] 表示以i?根，?通状??state的生成??
 */
    for (int i=1; i<=3; i++) st[i]=(1<<(i-1));
    endSt=(1<<3);
    n+=3;
    for (int i=1; i<=n; i++)
    for (int j=0; j<endSt; j++) dptree[i][j]=-1,g[i][j]=n+10;
    for(int i=1; i<=n; i++)
    {
        dptree[i][st[i]]=0;
        g[i][st[i]]=st[i]?n+10:i-3;
    }
}

void SPFA(int state)
{
    while(!que.empty()){
        int u=que.front();
        que.pop();
        vis[u][state]=false;
        for(int i=p[u];i!=-1;i=e[i].next){
            int v=e[i].vid;
            if(dptree[v][st[v]|state]==-1 ||
                dptree[v][st[v]|state]>dptree[u][state]+1){

                dptree[v][st[v]|state]=dptree[u][state]+1;
                g[v][st[v]|state]=min(st[v]?n+10:v-3,g[u][state]);
                if(st[v]|state!=state || vis[v][state])
                    continue; //只更新当前?通状?
                vis[v][state]=true;
                que.push(v);
            } else if (dptree[v][st[v]|state]==dptree[u][state]+1 && dptree[v][st[v]|state]!=-1) g[v][st[v]|state]=min(st[v]?n+10:v-3,g[u][state]);
        }
    }
}

void steinerTree()
{
    for(int j=1;j<endSt;j++){
        for(int i=1;i<=n;i++){
            if(st[i] && (st[i]&j)==0) continue;
            for(int sub=(j-1)&j;sub;sub=(sub-1)&j){
                int x=st[i]|sub,y=st[i]|(j-sub);
                if(dptree[i][x]!=-1 && dptree[i][y]!=-1)
                {
                    //update(dptree[i][j],dptree[i][x]+dptree[i][y]);
                    if (dptree[i][x]+dptree[i][y]<dptree[i][j] || dptree[i][j]==-1)
                    {
                        dptree[i][j]=dptree[i][x]+dptree[i][y];
                        g[i][j]=min(g[i][x],g[i][y]);
                    } else if (dptree[i][x]+dptree[i][y]==dptree[i][j] && dptree[i][j]!=-1 && min(g[i][x],g[i][y])<g[i][j])
                        g[i][j]=min(g[i][x],g[i][y]);
                }
            }
            if(dptree[i][j]!=-1)
                que.push(i),vis[i][j]=true;
        }
        SPFA(j);
    }
}

int main()
{
    input();
    steinerTree();
    ans=n+10;
    for (int i=1; i<=n; i++) if (dptree[i][endSt-1]!=-1) ans=min(ans,dptree[i][endSt-1]);
    for (int i=1; i<=n; i++) if (dptree[i][endSt-1]==ans) bns=min(bns,g[i][endSt-1]);
    printf("%d %d\n",ans,bns);
    return 0;
}

Measured memory_bytes: 13052