use std::collections::HashSet;
use std::collections::BTreeMap;
use std::fmt::Display;
use std::ops::Neg;
use std::ops::Div;
use std::ops::Mul;
use std::ops::Add;
use std::ops::{AddAssign, Sub};
use std::cmp::max;
use std::collections::VecDeque;
use std::cmp::min;
use std::collections::BTreeSet;
use std::cmp::Ordering;
use std::fmt::Debug;

fn read_line() -> String {
    let mut buffer = String::new();
    std::io::stdin().read_line(&mut buffer).expect("No Line");
    buffer
}
fn read_lines<T: std::str::FromStr>(count: usize) -> Vec<T> {
    let mut buffer = String::new();
    let mut vec = Vec::with_capacity(count);
    for _ in 0 .. count {
        std::io::stdin().read_line(&mut buffer).expect("No Line");
        vec.push(buffer.trim().parse().ok().expect("Can't Parse"));
        buffer.clear();
    }
    vec
}
fn read_tabulate<R, T: Fn(&str)->R> (count: usize, transformer: T) -> Vec<R> {
    let mut buffer = String::new();
    let mut vec = Vec::with_capacity(count);
    for _ in 0 .. count {
        std::io::stdin().read_line(&mut buffer).expect("No Line");
        vec.push(transformer(buffer.trim()));
        buffer.clear();
    }
    vec
}
fn read_value<T: std::str::FromStr>() -> T {
    read_line().trim().parse().ok().unwrap()
}
fn read_values<T: std::str::FromStr>() -> Vec<T> {
    read_line().trim().split(' ').map(|x| x.parse().ok().expect("Can't Parse")).collect::<Vec<T>>()
}
macro_rules! freeze {
    ($($id:ident), *) => {
        $(let $id = $id;)*
    };
}
macro_rules! read_lines {
    ($ident: ident: [$block: block; $size: expr]) => {
        let $ident = (0 .. $size).into_iter().map(|_| $block).collect::<Vec<_>>();
    };
    (mut $ident: ident: [$block: block; $size: expr]) => {
        let mut $ident = (0 .. $size).into_iter().map(|_| $block).collect::<Vec<_>>();
    };
}
macro_rules! read {
    (mut $ident: ident: [$ty:ty]) => {
        let mut $ident = read_values::<$ty>();
    };
    ($ident: ident: [$ty:ty]) => {
        let $ident = read_values::<$ty>();
    };
    (mut $ident: ident: [[$ty:ty]; $size: expr]) => {
        let mut $ident = (0 .. $size).into_iter().map(|_| read_values::<$ty>()).collect::<Vec<_>>();
    };
    ($ident: ident: [[$ty:ty]; $size: expr]) => {
        let $ident = (0 .. $size).into_iter().map(|_| read_values::<$ty>()).collect::<Vec<_>>();
    };
    (mut $ident: ident: [$ty:ty; $size:expr]) => {
        let mut $ident = read_lines::<$ty>($size);
    };
    ($ident: ident: [$ty:ty; $size:expr]) => {
        let $ident = read_lines::<$ty>($size);
    };
    ($ident: ident: [$block: block; $size: expr]) => {
        let $ident = (0 .. $size).into_iter().map(|_| $block).collect::<Vec<_>>();
    };
    (mut $ident: ident: [$block: block; $size: expr]) => {
        let mut $ident = (0 .. $size).into_iter().map(|_| $block).collect::<Vec<_>>();
    };
    ($($token: tt)*) => {
        let mut iter = read_values::<String>().into_iter();
        read_from_iter!(iter; $($token)*);
    };
}
macro_rules! read_from_iter {
    ($iter:expr; mut $ident:ident:$ty:ty, $($rest:tt)*) => {
        let mut $ident = $iter.next().unwrap().parse::<$ty>().expect("Can't Parse");
        read_from_iter!($iter; $($rest)*);
    };
    ($iter:expr; $ident:ident:$ty:ty, $($rest:tt)*) => {
        let $ident = $iter.next().unwrap().parse::<$ty>().expect("Can't Parse");
        read_from_iter!($iter; $($rest)*);
    };
    ($iter:expr; mut $ident:ident:$ty:ty) => {
        let mut $ident = $iter.next().unwrap().parse::<$ty>().expect("Can't Parse");
    };
    ($iter:expr; $ident:ident:$ty:ty) => {
        let $ident = $iter.next().unwrap().parse::<$ty>().expect("Can't Parse");
    };
    ($iter: expr; ) => {};
}
struct KeyValue<K, V> {
    key: K,
    value: V
}
impl <K: PartialOrd, V> PartialEq for KeyValue<K, V> {
    fn eq(&self, other: &Self) -> bool {
        self.key.eq(&other.key)
    }
}
impl <K: PartialOrd, V> Eq for KeyValue<K, V> {}
impl <K: PartialOrd, V> PartialOrd for KeyValue<K, V> {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        self.key.partial_cmp(&other.key)
    }
}
impl <K: PartialOrd, V> Ord for KeyValue<K, V> {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        self.key.partial_cmp(&other.key).ok_or("Can't Compare").unwrap()
    }
}
fn cal_depth(nodes: &Vec<Vec<usize>>, source: usize) -> Vec<i32> {
    let mut queue = VecDeque::new();
    queue.push_front(source);
    let mut result = vec![-1; nodes.len()];
    result[source] = 0;
    while let Some(top) = queue.pop_front() {
        for &next in &nodes[top] {
            if result[next] == -1 {
                result[next] = result[top] + 1;
                queue.push_back(next);
            }
        }
    }
    result
}
struct UnionFind {
    vec: Vec<i32>
}
impl UnionFind {
    fn new(size: usize) -> UnionFind {
        UnionFind{vec: vec![-1; size]}
    }
    fn find(&mut self, a: usize) -> usize {
        if self.vec[a] < 0 {
            a
        }else {
            let parent = self.vec[a] as usize;
            let root = self.find(parent);
            self.vec[a] = root as i32;
            root
        }
    }
    fn same(&mut self, a: usize, b: usize) -> bool {
        self.find(a) == self.find(b)
    }
    fn unite(&mut self, mut a: usize, mut b: usize) {
        a = self.find(a);
        b = self.find(b);
        if self.vec[a] < self.vec[b] {
            self.vec[a] += self.vec[b];
            self.vec[b] = a as i32;
        }else {
            self.vec[b] += self.vec[a];
            self.vec[a] = b as i32;
        }
    }
}
fn main() {
    read!{
        n: usize, a: usize, b: usize, c: usize
    }
    read!{
        a_students: [usize]
    }
    read! {
        b_students: [usize]
    }
    read! {
        c_students: [usize]
    }
    assert_eq!(a, a_students.len());
    assert_eq!(b, b_students.len());
    assert_eq!(c, c_students.len());
    let mut degree = vec![0usize; n + 4];
    for i in 1 .. 4 {
        degree[n + i] = i;
    }
    for &ai in &a_students {
        degree[ai] = 1;
    }
    for &bi in &b_students {
        degree[bi] = 2;
    }
    for &ci in &c_students {
        degree[ci] = 3;
    }
    read!{
        m: usize
    }
    read_lines! {
        links: [{
            read!(x: usize, y: usize);
            (x, y)
        }; m]
    }
    let mut nodes = vec![Vec::<usize>::new(); n + 4];
    for &(x, y) in &links {
        let x = if degree[x] != 0 {
            n + degree[x]
        }else {
            x
        };
        let y = if degree[y] != 0 {
            n + degree[y]
        }else {
            y
        };
        nodes[x].push(y);
        nodes[y].push(x);
    }
    let mut depth_from = vec![Vec::new(); 4];
    for i in 1 .. 4 {
        let depth = cal_depth(&nodes, n + i);
        depth_from[i] = depth;
    }
    let min_cost = (0 .. n + 4).map(|mut x| {
        x = if degree[x] != 0 {n + degree[x]} else {x};
        if (1 .. 4).any(|i| depth_from[i][x] < 0) {
            std::i32::MAX
        }else {
            (1 .. 4).map(|i| depth_from[i][x]).sum()
        }
    }).collect::<Vec<_>>();
    let &result = min_cost.iter().min().unwrap();
    let mut on_min_path_to = vec![vec![false; n + 4]; 4];
    for i in 1 .. n + 4 {
        if min_cost[i] != result { continue; }
        for to in 1 .. 4 {
            if on_min_path_to[to][i] {continue;}
            on_min_path_to[to][i] = true;
            let mut queue = VecDeque::new(); queue.push_back(i);
            while let Some(top) = queue.pop_front() {
                for &next in &nodes[top] {
                    if on_min_path_to[to][next] {continue;}
                    if depth_from[to][next] + 1 != depth_from[to][top] {continue;}
                    on_min_path_to[to][next] = true;
                    queue.push_back(next);
                }
            }
        }
    }
    let first = (1 .. n + 1).find(|&i| {
        degree[i] != 0 || (1 .. 4).any(|to| on_min_path_to[to][i])
    }).unwrap();
    println!("{} {}", result, first);
}



Measured memory_bytes: 27264