Ivan wants to have a good dinner. A good dinner should consist of a first course, a second course, a drink, and a dessert.There are $$$n_1$$$ different types of first courses Ivan can buy (the $$$i$$$-th of them costs $$$a_i$$$ coins), $$$n_2$$$ different types of second courses (the $$$i$$$-th of them costs $$$b_i$$$ coins), $$$n_3$$$ different types of drinks (the $$$i$$$-th of them costs $$$c_i$$$ coins) and $$$n_4$$$ different types of desserts (the $$$i$$$-th of them costs $$$d_i$$$ coins).Some dishes don't go well with each other. There are $$$m_1$$$ pairs of first courses and second courses that don't go well with each other, $$$m_2$$$ pairs of second courses and drinks, and $$$m_3$$$ pairs of drinks and desserts that don't go well with each other.Ivan wants to buy exactly one first course, one second course, one drink, and one dessert so that they go well with each other, and the total cost of the dinner is the minimum possible. Help him to find the cheapest dinner option!

The first line contains four integers $$$n_1$$$, $$$n_2$$$, $$$n_3$$$ and $$$n_4$$$ ($$$1 \le n_i \le 150000$$$) — the number of types of first courses, second courses, drinks and desserts, respectively. Then four lines follow. The first line contains $$$n_1$$$ integers $$$a_1, a_2, \dots, a_{n_1}$$$ ($$$1 \le a_i \le 10^8$$$), where $$$a_i$$$ is the cost of the $$$i$$$-th type of first course. Three next lines denote the costs of second courses, drinks, and desserts in the same way ($$$1 \le b_i, c_i, d_i \le 10^8$$$). The next line contains one integer $$$m_1$$$ ($$$0 \le m_1 \le 200000$$$) — the number of pairs of first and second courses that don't go well with each other. Each of the next $$$m_1$$$ lines contains two integers $$$x_i$$$ and $$$y_i$$$ ($$$1 \le x_i \le n_1$$$; $$$1 \le y_i \le n_2$$$) denoting that the first course number $$$x_i$$$ doesn't go well with the second course number $$$y_i$$$. All these pairs are different. The block of pairs of second dishes and drinks that don't go well with each other is given in the same format. The same for pairs of drinks and desserts that don't go well with each other ($$$0 \le m_2, m_3 \le 200000$$$).

If it's impossible to choose a first course, a second course, a drink, and a dessert so that they go well with each other, print $$$-1$$$. Otherwise, print one integer — the minimum total cost of the dinner.

NoteThe best option in the first example is to take the first course $$$2$$$, the second course $$$1$$$, the drink $$$2$$$ and the dessert $$$1$$$.In the second example, the only pair of the first course and the second course is bad, so it's impossible to have dinner.

package main

import (
	"bufio"
	"fmt"
	"os"
	"sort"
)

func main() {
	reader := bufio.NewReader(os.Stdin)

	first := readNNums(reader, 4)
	A := readNNums(reader, first[0])
	B := readNNums(reader, first[1])
	C := readNNums(reader, first[2])
	D := readNNums(reader, first[3])

	m := readNum(reader)
	X := make([][]int, m)
	for i := 0; i < m; i++ {
		X[i] = readNNums(reader, 2)
	}
	m = readNum(reader)
	Y := make([][]int, m)
	for i := 0; i < m; i++ {
		Y[i] = readNNums(reader, 2)
	}
	m = readNum(reader)
	Z := make([][]int, m)
	for i := 0; i < m; i++ {
		Z[i] = readNNums(reader, 2)
	}
	fmt.Println(solve1(A, B, C, D, X, Y, Z))
}

func readInt(bytes []byte, from int, val *int) int {
	i := from
	sign := 1
	if bytes[i] == '-' {
		sign = -1
		i++
	}
	tmp := 0
	for i < len(bytes) && bytes[i] >= '0' && bytes[i] <= '9' {
		tmp = tmp*10 + int(bytes[i]-'0')
		i++
	}
	*val = tmp * sign
	return i
}

func readNum(reader *bufio.Reader) (a int) {
	bs, _ := reader.ReadBytes('\n')
	readInt(bs, 0, &a)
	return
}

func readTwoNums(reader *bufio.Reader) (a int, b int) {
	res := readNNums(reader, 2)
	a, b = res[0], res[1]
	return
}

func readThreeNums(reader *bufio.Reader) (a int, b int, c int) {
	res := readNNums(reader, 3)
	a, b, c = res[0], res[1], res[2]
	return
}

func readNNums(reader *bufio.Reader, n int) []int {
	res := make([]int, n)
	x := 0
	bs, _ := reader.ReadBytes('\n')
	for i := 0; i < n; i++ {
		for x < len(bs) && (bs[x] < '0' || bs[x] > '9') && bs[x] != '-' {
			x++
		}
		x = readInt(bs, x, &res[i])
	}
	return res
}

func readUint64(bytes []byte, from int, val *uint64) int {
	i := from

	var tmp uint64
	for i < len(bytes) && bytes[i] >= '0' && bytes[i] <= '9' {
		tmp = tmp*10 + uint64(bytes[i]-'0')
		i++
	}
	*val = tmp

	return i
}

const MAX_N = 150010
const INF = 400000010

func solve(A, B, C, D []int, X, Y, Z [][]int) int {

	proc := func(a, b []int, c [][]int) []int {
		n1 := len(a)
		n2 := len(b)
		m := len(c)
		g := NewGraph(n1+n2, m)

		for _, x := range c {
			u, v := x[0], x[1]
			u--
			v--
			g.AddEdge(u, v+n1)
		}
		var set *Node
		for i := 0; i < n2; i++ {
			if b[i] < INF {
				set = Insert(set, b[i])
			}
		}
		res := make([]int, n1)
		for u := 0; u < n1; u++ {
			for i := g.nodes[u]; i > 0; i = g.next[i] {
				v := g.to[i] - n1
				if b[v] < INF {
					set = Delete(set, b[v])
				}
			}
			res[u] = INF
			if set != nil {
				res[u] = MinValueNode(set).key + a[u]
			}

			for i := g.nodes[u]; i > 0; i = g.next[i] {
				v := g.to[i] - n1
				if b[v] < INF {
					set = Insert(set, b[v])
				}
			}
		}
		return res
	}

	R := proc(C, D, Z)
	R = proc(B, R, Y)
	R = proc(A, R, X)
	var best int = INF
	for i := 0; i < len(R); i++ {
		best = min(best, R[i])
	}
	if best >= INF {
		return -1
	}
	return best
}

type Graph struct {
	nodes []int
	next  []int
	to    []int
	cur   int
}

func NewGraph(n int, e int) *Graph {
	nodes := make([]int, n)
	next := make([]int, e+3)
	to := make([]int, e+3)
	return &Graph{nodes, next, to, 0}
}

func (g *Graph) AddEdge(u, v int) {
	g.cur++
	g.next[g.cur] = g.nodes[u]
	g.nodes[u] = g.cur
	g.to[g.cur] = v
}

/**
* this is a AVL tree
 */
type Node struct {
	key         int
	height      int
	cnt         int
	left, right *Node
}

func (node *Node) Height() int {
	if node == nil {
		return 0
	}
	return node.height
}

func max(a, b int) int {
	if a >= b {
		return a
	}
	return b
}

func NewNode(key int) *Node {
	node := new(Node)
	node.key = key
	node.height = 1
	node.cnt = 1
	return node
}

func rightRotate(y *Node) *Node {
	x := y.left

	t2 := x.right

	x.right = y
	y.left = t2
	y.height = max(y.left.Height(), y.right.Height()) + 1
	x.height = max(x.left.Height(), x.right.Height()) + 1

	return x
}

func leftRotate(x *Node) *Node {
	y := x.right
	t2 := y.left

	y.left = x
	x.right = t2

	x.height = max(x.left.Height(), x.right.Height()) + 1
	y.height = max(y.left.Height(), y.right.Height()) + 1

	return y
}

func (node *Node) GetBalance() int {
	if node == nil {
		return 0
	}
	return node.left.Height() - node.right.Height()
}

func Insert(node *Node, key int) *Node {
	if node == nil {
		return NewNode(key)
	}
	if node.key == key {
		node.cnt++
		return node
	}

	if node.key > key {
		node.left = Insert(node.left, key)
	} else {
		node.right = Insert(node.right, key)
	}

	node.height = max(node.left.Height(), node.right.Height()) + 1
	balance := node.GetBalance()

	if balance > 1 && key < node.left.key {
		return rightRotate(node)
	}

	if balance < -1 && key > node.right.key {
		return leftRotate(node)
	}

	if balance > 1 && key > node.left.key {
		node.left = leftRotate(node.left)
		return rightRotate(node)
	}

	if balance < -1 && key < node.right.key {
		node.right = rightRotate(node.right)
		return leftRotate(node)
	}

	return node
}

func MinValueNode(root *Node) *Node {
	cur := root

	for cur.left != nil {
		cur = cur.left
	}

	return cur
}

func (root *Node) MinValue() int {
	if root == nil {
		return 0
	}
	node := MinValueNode(root)

	return node.key
}

func Delete(root *Node, key int) *Node {
	if root == nil {
		return nil
	}

	if key < root.key {
		root.left = Delete(root.left, key)
	} else if key > root.key {
		root.right = Delete(root.right, key)
	} else {
		root.cnt--
		if root.cnt > 0 {
			return root
		}
		if root.left == nil || root.right == nil {
			tmp := root.left
			if root.left == nil {
				tmp = root.right
			}
			root = tmp
		} else {
			tmp := MinValueNode(root.right)

			root.key = tmp.key
			root.cnt = tmp.cnt
			// make sure tmp node deleted after call delete on root.right
			tmp.cnt = 1
			root.right = Delete(root.right, tmp.key)
		}
	}

	if root == nil {
		return root
	}

	root.height = max(root.left.Height(), root.right.Height()) + 1
	balance := root.GetBalance()

	if balance > 1 && root.left.GetBalance() >= 0 {
		return rightRotate(root)
	}

	if balance > 1 && root.left.GetBalance() < 0 {
		root.left = leftRotate(root.left)
		return rightRotate(root)
	}

	if balance < -1 && root.right.GetBalance() <= 0 {
		return leftRotate(root)
	}

	if balance < -1 && root.right.GetBalance() > 0 {
		root.right = rightRotate(root.right)
		return leftRotate(root)
	}

	return root
}

func solve1(A, B, C, D []int, X, Y, Z [][]int) int {
	R := process(C, D, Z)
	R = process(B, R, Y)
	R = process(A, R, X)
	var best int = INF
	for i := 0; i < len(R); i++ {
		best = min(best, R[i])
	}
	if best >= INF {
		return -1
	}
	return best
}

func process(A, B []int, X [][]int) []int {
	n1 := len(A)
	n2 := len(B)
	sort.Slice(X, func(i, j int) bool {
		return X[i][1] < X[j][1]
	})

	tree := NewTree(n2)

	for i := 0; i < n2; i++ {
		tree.Update(i, B[i])
	}

	cnt := make([]int, n1)

	for _, x := range X {
		cnt[x[0]-1]++
	}

	conn := make([][]int, n1)

	for i := 0; i < n1; i++ {
		conn[i] = make([]int, 0, cnt[i])
	}

	for _, x := range X {
		u, v := x[0], x[1]
		u--
		v--
		conn[u] = append(conn[u], v)
	}
	res := make([]int, n1)
	for u := 0; u < n1; u++ {
		res[u] = INF
		var p int
		for _, v := range conn[u] {
			if p < v {
				tmp := tree.Query(p, v)
				res[u] = min(res[u], tmp+A[u])
			}
			p = v + 1
		}
		if p < n2 {
			res[u] = min(res[u], tree.Query(p, n2)+A[u])
		}
	}
	return res
}

type Tree struct {
	arr []int
	n   int
}

func NewTree(n int) *Tree {
	arr := make([]int, n*2)
	for i := 0; i < len(arr); i++ {
		arr[i] = INF
	}
	return &Tree{arr, n}
}

func (tree *Tree) Update(p int, v int) {
	p += tree.n
	if tree.arr[p] > v {
		tree.arr[p] = v
		for p > 1 {
			tree.arr[p>>1] = min(tree.arr[p], tree.arr[p^1])
			p >>= 1
		}
	}
}

func (tree *Tree) Query(l, r int) int {
	l += tree.n
	r += tree.n
	res := INF
	for l < r {
		if l&1 == 1 {
			res = min(res, tree.arr[l])
			l++
		}
		if r&1 == 1 {
			r--
			res = min(res, tree.arr[r])
		}
		l >>= 1
		r >>= 1
	}
	return res
}

type SegTree struct {
	arr  []int
	lazy []int
	n    int
}

func NewSegTree(n int) *SegTree {
	arr := make([]int, 4*n)
	lazy := make([]int, 4*n)
	for i := 0; i < len(arr); i++ {
		arr[i] = INF + 1
	}
	return &SegTree{arr, lazy, n}
}

func (tree *SegTree) Update(L, R int, V int) {
	var loop func(i int, l, r int)
	loop = func(i int, l, r int) {
		if r < L || R < l {
			return
		}
		if L <= l && r <= R {
			tree.change(i, V)
			return
		}
		tree.push(i)
		mid := (l + r) / 2
		loop(2*i, l, mid)
		loop(2*i+1, mid+1, r)
		tree.arr[i] = min(tree.arr[2*i], tree.arr[2*i+1])
	}
	loop(1, 0, tree.n-1)
}

func (tree *SegTree) Query(L, R int) int {
	var loop func(i int, l, r int) int
	loop = func(i int, l, r int) int {
		if r < L || R < l {
			return INF
		}
		if L <= l && r <= R {
			return tree.arr[i]
		}

		tree.push(i)

		mid := (l + r) / 2
		a := loop(2*i, l, mid)
		b := loop(2*i+1, mid+1, r)
		return min(a, b)
	}
	return loop(1, 0, tree.n-1)
}

func (tree *SegTree) change(id int, v int) {
	if tree.arr[id] > v {
		tree.arr[id] = v
		tree.lazy[id] = v
	}
}

func (tree *SegTree) push(id int) {
	if tree.lazy[id] > 0 {
		tree.change(id*2, tree.lazy[id])
		tree.change(id*2+1, tree.lazy[id])
		tree.lazy[id] = 0
	}
}

func min(a, b int) int {
	if a <= b {
		return a
	}
	return b
}

package main

import (
	"bufio"
	"fmt"
	"os"
	"sort"
)

func main() {
	reader := bufio.NewReader(os.Stdin)

	first := readNNums(reader, 4)
	A := readNNums(reader, first[0])
	B := readNNums(reader, first[1])
	C := readNNums(reader, first[2])
	D := readNNums(reader, first[3])

	m := readNum(reader)
	X := make([][]int, m)
	for i := 0; i < m; i++ {
		X[i] = readNNums(reader, 2)
	}
	m = readNum(reader)
	Y := make([][]int, m)
	for i := 0; i < m; i++ {
		Y[i] = readNNums(reader, 2)
	}
	m = readNum(reader)
	Z := make([][]int, m)
	for i := 0; i < m; i++ {
		Z[i] = readNNums(reader, 2)
	}
	fmt.Println(solve1(A, B, C, D, X, Y, Z))
}

func readInt(bytes []byte, from int, val *int) int {
	i := from
	sign := 1
	if bytes[i] == '-' {
		sign = -1
		i++
	}
	tmp := 0
	for i < len(bytes) && bytes[i] >= '0' && bytes[i] <= '9' {
		tmp = tmp*10 + int(bytes[i]-'0')
		i++
	}
	*val = tmp * sign
	return i
}

func readNum(reader *bufio.Reader) (a int) {
	bs, _ := reader.ReadBytes('\n')
	readInt(bs, 0, &a)
	return
}

func readTwoNums(reader *bufio.Reader) (a int, b int) {
	res := readNNums(reader, 2)
	a, b = res[0], res[1]
	return
}

func readThreeNums(reader *bufio.Reader) (a int, b int, c int) {
	res := readNNums(reader, 3)
	a, b, c = res[0], res[1], res[2]
	return
}

func readNNums(reader *bufio.Reader, n int) []int {
	res := make([]int, n)
	x := 0
	bs, _ := reader.ReadBytes('\n')
	for i := 0; i < n; i++ {
		for x < len(bs) && (bs[x] < '0' || bs[x] > '9') && bs[x] != '-' {
			x++
		}
		x = readInt(bs, x, &res[i])
	}
	return res
}

func readUint64(bytes []byte, from int, val *uint64) int {
	i := from

	var tmp uint64
	for i < len(bytes) && bytes[i] >= '0' && bytes[i] <= '9' {
		tmp = tmp*10 + uint64(bytes[i]-'0')
		i++
	}
	*val = tmp

	return i
}

const MAX_N = 150010
const INF = 400000010

func solve(A, B, C, D []int, X, Y, Z [][]int) int {

	proc := func(a, b []int, c [][]int) []int {
		n1 := len(a)
		n2 := len(b)
		m := len(c)
		g := NewGraph(n1+n2, m)

		for _, x := range c {
			u, v := x[0], x[1]
			u--
			v--
			g.AddEdge(u, v+n1)
		}
		var set *Node
		for i := 0; i < n2; i++ {
			if b[i] < INF {
				set = Insert(set, b[i])
			}
		}
		res := make([]int, n1)
		for u := 0; u < n1; u++ {
			for i := g.nodes[u]; i > 0; i = g.next[i] {
				v := g.to[i] - n1
				if b[v] < INF {
					set = Delete(set, b[v])
				}
			}
			res[u] = INF
			if set != nil {
				res[u] = MinValueNode(set).key + a[u]
			}

			for i := g.nodes[u]; i > 0; i = g.next[i] {
				v := g.to[i] - n1
				if b[v] < INF {
					set = Insert(set, b[v])
				}
			}
		}
		return res
	}

	R := proc(C, D, Z)
	R = proc(B, R, Y)
	R = proc(A, R, X)
	var best int = INF
	for i := 0; i < len(R); i++ {
		best = min(best, R[i])
	}
	if best >= INF {
		return -1
	}
	return best
}

type Graph struct {
	nodes []int
	next  []int
	to    []int
	cur   int
}

func NewGraph(n int, e int) *Graph {
	nodes := make([]int, n)
	next := make([]int, e+3)
	to := make([]int, e+3)
	return &Graph{nodes, next, to, 0}
}

func (g *Graph) AddEdge(u, v int) {
	g.cur++
	g.next[g.cur] = g.nodes[u]
	g.nodes[u] = g.cur
	g.to[g.cur] = v
}

/**
* this is a AVL tree
 */
type Node struct {
	key         int
	height      int
	cnt         int
	left, right *Node
}

func (node *Node) Height() int {
	if node == nil {
		return 0
	}
	return node.height
}

func max(a, b int) int {
	if a >= b {
		return a
	}
	return b
}

func NewNode(key int) *Node {
	node := new(Node)
	node.key = key
	node.height = 1
	node.cnt = 1
	return node
}

func rightRotate(y *Node) *Node {
	x := y.left

	t2 := x.right

	x.right = y
	y.left = t2
	y.height = max(y.left.Height(), y.right.Height()) + 1
	x.height = max(x.left.Height(), x.right.Height()) + 1

	return x
}

func leftRotate(x *Node) *Node {
	y := x.right
	t2 := y.left

	y.left = x
	x.right = t2

	x.height = max(x.left.Height(), x.right.Height()) + 1
	y.height = max(y.left.Height(), y.right.Height()) + 1

	return y
}

func (node *Node) GetBalance() int {
	if node == nil {
		return 0
	}
	return node.left.Height() - node.right.Height()
}

func Insert(node *Node, key int) *Node {
	if node == nil {
		return NewNode(key)
	}
	if node.key == key {
		node.cnt++
		return node
	}

	if node.key > key {
		node.left = Insert(node.left, key)
	} else {
		node.right = Insert(node.right, key)
	}

	node.height = max(node.left.Height(), node.right.Height()) + 1
	balance := node.GetBalance()

	if balance > 1 && key < node.left.key {
		return rightRotate(node)
	}

	if balance < -1 && key > node.right.key {
		return leftRotate(node)
	}

	if balance > 1 && key > node.left.key {
		node.left = leftRotate(node.left)
		return rightRotate(node)
	}

	if balance < -1 && key < node.right.key {
		node.right = rightRotate(node.right)
		return leftRotate(node)
	}

	return node
}

func MinValueNode(root *Node) *Node {
	cur := root

	for cur.left != nil {
		cur = cur.left
	}

	return cur
}

func (root *Node) MinValue() int {
	if root == nil {
		return 0
	}
	node := MinValueNode(root)

	return node.key
}

func Delete(root *Node, key int) *Node {
	if root == nil {
		return nil
	}

	if key < root.key {
		root.left = Delete(root.left, key)
	} else if key > root.key {
		root.right = Delete(root.right, key)
	} else {
		root.cnt--
		if root.cnt > 0 {
			return root
		}
		if root.left == nil || root.right == nil {
			tmp := root.left
			if root.left == nil {
				tmp = root.right
			}
			root = tmp
		} else {
			tmp := MinValueNode(root.right)

			root.key = tmp.key
			root.cnt = tmp.cnt
			// make sure tmp node deleted after call delete on root.right
			tmp.cnt = 1
			root.right = Delete(root.right, tmp.key)
		}
	}

	if root == nil {
		return root
	}

	root.height = max(root.left.Height(), root.right.Height()) + 1
	balance := root.GetBalance()

	if balance > 1 && root.left.GetBalance() >= 0 {
		return rightRotate(root)
	}

	if balance > 1 && root.left.GetBalance() < 0 {
		root.left = leftRotate(root.left)
		return rightRotate(root)
	}

	if balance < -1 && root.right.GetBalance() <= 0 {
		return leftRotate(root)
	}

	if balance < -1 && root.right.GetBalance() > 0 {
		root.right = rightRotate(root.right)
		return leftRotate(root)
	}

	return root
}

func solve1(A, B, C, D []int, X, Y, Z [][]int) int {
	R := process(C, D, Z)
	R = process(B, R, Y)
	R = process(A, R, X)
	var best int = INF
	for i := 0; i < len(R); i++ {
		best = min(best, R[i])
	}
	if best >= INF {
		return -1
	}
	return best
}

func process(A, B []int, X [][]int) []int {
	n1 := len(A)
	n2 := len(B)
	sort.Slice(X, func(i, j int) bool {
		return X[i][1] < X[j][1]
	})

	tree := NewSegTree(n2)

	for i := 0; i < n2; i++ {
		tree.Update(i, i, B[i])
	}

	cnt := make([]int, n1)

	for _, x := range X {
		cnt[x[0]-1]++
	}

	conn := make([][]int, n1)

	for i := 0; i < n1; i++ {
		conn[i] = make([]int, 0, cnt[i])
	}

	for _, x := range X {
		u, v := x[0], x[1]
		u--
		v--
		conn[u] = append(conn[u], v)
	}
	res := make([]int, n1)
	for u := 0; u < n1; u++ {
		res[u] = INF
		var p int
		for _, v := range conn[u] {
			if p < v {
				tmp := tree.Query(p, v-1)
				res[u] = min(res[u], tmp+A[u])
			}
			p = v + 1
		}
		if p < n2 {
			res[u] = min(res[u], tree.Query(p, n2-1)+A[u])
		}
	}
	return res
}

type SegTree struct {
	arr  []int
	lazy []int
	n    int
}

func NewSegTree(n int) *SegTree {
	arr := make([]int, 4*n)
	lazy := make([]int, 4*n)
	for i := 0; i < len(arr); i++ {
		arr[i] = INF + 1
	}
	return &SegTree{arr, lazy, n}
}

func (tree *SegTree) Update(L, R int, V int) {
	var loop func(i int, l, r int)
	loop = func(i int, l, r int) {
		if r < L || R < l {
			return
		}
		if L <= l && r <= R {
			tree.change(i, V)
			return
		}
		tree.push(i)
		mid := (l + r) / 2
		loop(2*i, l, mid)
		loop(2*i+1, mid+1, r)
		tree.arr[i] = min(tree.arr[2*i], tree.arr[2*i+1])
	}
	loop(1, 0, tree.n-1)
}

func (tree *SegTree) Query(L, R int) int {
	var loop func(i int, l, r int) int
	loop = func(i int, l, r int) int {
		if r < L || R < l {
			return INF
		}
		if L <= l && r <= R {
			return tree.arr[i]
		}

		tree.push(i)

		mid := (l + r) / 2
		a := loop(2*i, l, mid)
		b := loop(2*i+1, mid+1, r)
		return min(a, b)
	}
	return loop(1, 0, tree.n-1)
}

func (tree *SegTree) change(id int, v int) {
	if tree.arr[id] > v {
		tree.arr[id] = v
		tree.lazy[id] = v
	}
}

func (tree *SegTree) push(id int) {
	if tree.lazy[id] > 0 {
		tree.change(id*2, tree.lazy[id])
		tree.change(id*2+1, tree.lazy[id])
		tree.lazy[id] = 0
	}
}

func min(a, b int) int {
	if a <= b {
		return a
	}
	return b
}

package main

import (
	"bufio"
	"fmt"
	"os"
	"sort"
)

func main() {
	reader := bufio.NewReader(os.Stdin)

	first := readNNums(reader, 4)
	A := readNNums(reader, first[0])
	B := readNNums(reader, first[1])
	C := readNNums(reader, first[2])
	D := readNNums(reader, first[3])

	m := readNum(reader)
	X := make([][]int, m)
	for i := 0; i < m; i++ {
		X[i] = readNNums(reader, 2)
	}
	m = readNum(reader)
	Y := make([][]int, m)
	for i := 0; i < m; i++ {
		Y[i] = readNNums(reader, 2)
	}
	m = readNum(reader)
	Z := make([][]int, m)
	for i := 0; i < m; i++ {
		Z[i] = readNNums(reader, 2)
	}
	fmt.Println(solve(A, B, C, D, X, Y, Z))
}

func readInt(bytes []byte, from int, val *int) int {
	i := from
	sign := 1
	if bytes[i] == '-' {
		sign = -1
		i++
	}
	tmp := 0
	for i < len(bytes) && bytes[i] >= '0' && bytes[i] <= '9' {
		tmp = tmp*10 + int(bytes[i]-'0')
		i++
	}
	*val = tmp * sign
	return i
}

func readNum(reader *bufio.Reader) (a int) {
	bs, _ := reader.ReadBytes('\n')
	readInt(bs, 0, &a)
	return
}

func readTwoNums(reader *bufio.Reader) (a int, b int) {
	res := readNNums(reader, 2)
	a, b = res[0], res[1]
	return
}

func readThreeNums(reader *bufio.Reader) (a int, b int, c int) {
	res := readNNums(reader, 3)
	a, b, c = res[0], res[1], res[2]
	return
}

func readNNums(reader *bufio.Reader, n int) []int {
	res := make([]int, n)
	x := 0
	bs, _ := reader.ReadBytes('\n')
	for i := 0; i < n; i++ {
		for x < len(bs) && (bs[x] < '0' || bs[x] > '9') && bs[x] != '-' {
			x++
		}
		x = readInt(bs, x, &res[i])
	}
	return res
}

func readUint64(bytes []byte, from int, val *uint64) int {
	i := from

	var tmp uint64
	for i < len(bytes) && bytes[i] >= '0' && bytes[i] <= '9' {
		tmp = tmp*10 + uint64(bytes[i]-'0')
		i++
	}
	*val = tmp

	return i
}

const MAX_N = 150010
const INF = 400000010

func solve(A, B, C, D []int, X, Y, Z [][]int) int {

	proc := func(a, b []int, c [][]int) []int {
		n1 := len(a)
		n2 := len(b)
		m := len(c)
		g := NewGraph(n1+n2, m)

		for _, x := range c {
			u, v := x[0], x[1]
			u--
			v--
			g.AddEdge(u, v+n1)
		}
		var set *Node
		for i := 0; i < n2; i++ {
			if b[i] < INF {
				set = Insert(set, b[i])
			}
		}
		res := make([]int, n1)
		for u := 0; u < n1; u++ {
			for i := g.nodes[u]; i > 0; i = g.next[i] {
				v := g.to[i] - n1
				if b[v] < INF {
					set = Delete(set, b[v])
				}
			}
			res[u] = INF
			if set != nil {
				res[u] = MinValueNode(set).key + a[u]
			}

			for i := g.nodes[u]; i > 0; i = g.next[i] {
				v := g.to[i] - n1
				if b[v] < INF {
					set = Insert(set, b[v])
				}
			}
		}
		return res
	}

	R := proc(C, D, Z)
	R = proc(B, R, Y)
	R = proc(A, R, X)
	var best int = INF
	for i := 0; i < len(R); i++ {
		best = min(best, R[i])
	}
	if best >= INF {
		return -1
	}
	return best
}

type Graph struct {
	nodes []int
	next  []int
	to    []int
	cur   int
}

func NewGraph(n int, e int) *Graph {
	nodes := make([]int, n)
	next := make([]int, e+3)
	to := make([]int, e+3)
	return &Graph{nodes, next, to, 0}
}

func (g *Graph) AddEdge(u, v int) {
	g.cur++
	g.next[g.cur] = g.nodes[u]
	g.nodes[u] = g.cur
	g.to[g.cur] = v
}

/**
* this is a AVL tree
 */
type Node struct {
	key         int
	height      int
	cnt         int
	left, right *Node
}

func (node *Node) Height() int {
	if node == nil {
		return 0
	}
	return node.height
}

func max(a, b int) int {
	if a >= b {
		return a
	}
	return b
}

func NewNode(key int) *Node {
	node := new(Node)
	node.key = key
	node.height = 1
	node.cnt = 1
	return node
}

func rightRotate(y *Node) *Node {
	x := y.left

	t2 := x.right

	x.right = y
	y.left = t2
	y.height = max(y.left.Height(), y.right.Height()) + 1
	x.height = max(x.left.Height(), x.right.Height()) + 1

	return x
}

func leftRotate(x *Node) *Node {
	y := x.right
	t2 := y.left

	y.left = x
	x.right = t2

	x.height = max(x.left.Height(), x.right.Height()) + 1
	y.height = max(y.left.Height(), y.right.Height()) + 1

	return y
}

func (node *Node) GetBalance() int {
	if node == nil {
		return 0
	}
	return node.left.Height() - node.right.Height()
}

func Insert(node *Node, key int) *Node {
	if node == nil {
		return NewNode(key)
	}
	if node.key == key {
		node.cnt++
		return node
	}

	if node.key > key {
		node.left = Insert(node.left, key)
	} else {
		node.right = Insert(node.right, key)
	}

	node.height = max(node.left.Height(), node.right.Height()) + 1
	balance := node.GetBalance()

	if balance > 1 && key < node.left.key {
		return rightRotate(node)
	}

	if balance < -1 && key > node.right.key {
		return leftRotate(node)
	}

	if balance > 1 && key > node.left.key {
		node.left = leftRotate(node.left)
		return rightRotate(node)
	}

	if balance < -1 && key < node.right.key {
		node.right = rightRotate(node.right)
		return leftRotate(node)
	}

	return node
}

func MinValueNode(root *Node) *Node {
	cur := root

	for cur.left != nil {
		cur = cur.left
	}

	return cur
}

func (root *Node) MinValue() int {
	if root == nil {
		return 0
	}
	node := MinValueNode(root)

	return node.key
}

func Delete(root *Node, key int) *Node {
	if root == nil {
		return nil
	}

	if key < root.key {
		root.left = Delete(root.left, key)
	} else if key > root.key {
		root.right = Delete(root.right, key)
	} else {
		root.cnt--
		if root.cnt > 0 {
			return root
		}
		if root.left == nil || root.right == nil {
			tmp := root.left
			if root.left == nil {
				tmp = root.right
			}
			root = tmp
		} else {
			tmp := MinValueNode(root.right)

			root.key = tmp.key
			root.cnt = tmp.cnt
			// make sure tmp node deleted after call delete on root.right
			tmp.cnt = 1
			root.right = Delete(root.right, tmp.key)
		}
	}

	if root == nil {
		return root
	}

	root.height = max(root.left.Height(), root.right.Height()) + 1
	balance := root.GetBalance()

	if balance > 1 && root.left.GetBalance() >= 0 {
		return rightRotate(root)
	}

	if balance > 1 && root.left.GetBalance() < 0 {
		root.left = leftRotate(root.left)
		return rightRotate(root)
	}

	if balance < -1 && root.right.GetBalance() <= 0 {
		return leftRotate(root)
	}

	if balance < -1 && root.right.GetBalance() > 0 {
		root.right = rightRotate(root.right)
		return leftRotate(root)
	}

	return root
}

func solve1(A, B, C, D []int, X, Y, Z [][]int) int {
	R := process(C, D, Z)
	R = process(B, R, Y)
	R = process(A, R, X)
	var best int = INF
	for i := 0; i < len(R); i++ {
		best = min(best, R[i])
	}
	if best >= INF {
		return -1
	}
	return best
}

func process(A, B []int, X [][]int) []int {
	n1 := len(A)
	n2 := len(B)
	cnt := make([]int, n2)
	for _, x := range X {
		cnt[x[1]-1]++
	}

	pref := make([][]int, n2)
	for i := 0; i < n2; i++ {
		pref[i] = make([]int, 0, cnt[i])
	}

	sort.Slice(X, func(i, j int) bool {
		return X[i][0] < X[j][0]
	})

	for _, x := range X {
		a, b := x[0], x[1]
		a--
		b--
		if B[b] >= INF {
			continue
		}
		pref[b] = append(pref[b], a)
	}

	tree := NewSegTree(n1)

	for i := 0; i < n2; i++ {
		if B[i] >= INF {
			continue
		}
		cur := pref[i]
		//sort.Ints(cur)
		var p int
		for j := 0; j < len(cur); j++ {
			if cur[j] > p {
				tree.Update(p, cur[j]-1, B[i])
			}
			p = cur[j] + 1
		}
		if p < n1 {
			tree.Update(p, n1-1, B[i])
		}
	}

	res := make([]int, n1)

	for i := 0; i < n1; i++ {
		tmp := tree.Query(i, i)
		if tmp < INF {
			res[i] = tmp + A[i]
		} else {
			res[i] = INF
		}
	}
	return res
}

type SegTree struct {
	arr  []int
	lazy []int
	n    int
}

func NewSegTree(n int) *SegTree {
	arr := make([]int, 4*n)
	for i := 0; i < len(arr); i++ {
		arr[i] = INF
	}
	lazy := make([]int, 4*n)
	return &SegTree{arr, lazy, n}
}

func (tree *SegTree) Update(L, R int, V int) {
	var loop func(i int, l, r int)
	loop = func(i int, l, r int) {
		if r < L || R < l {
			return
		}
		if L <= l && r <= R {
			tree.change(i, V)
			return
		}
		tree.push(i)
		mid := (l + r) / 2
		loop(2*i, l, mid)
		loop(2*i+1, mid+1, r)
		tree.arr[i] = min(tree.arr[2*i], tree.arr[2*i+1])
	}
	loop(1, 0, tree.n-1)
}

func (tree *SegTree) Query(L, R int) int {
	var loop func(i int, l, r int) int
	loop = func(i int, l, r int) int {
		if r < L || R < l {
			return INF
		}
		if L <= l && r <= R {
			return tree.arr[i]
		}

		tree.push(i)

		mid := (l + r) / 2
		a := loop(2*i, l, mid)
		b := loop(2*i+1, mid+1, r)
		return min(a, b)
	}
	return loop(1, 0, tree.n-1)
}

func (tree *SegTree) change(id int, v int) {
	if tree.arr[id] > v {
		tree.arr[id] = v
		tree.lazy[id] = v
	}
}

func (tree *SegTree) push(id int) {
	if tree.lazy[id] > 0 {
		tree.change(id*2, tree.lazy[id])
		tree.change(id*2+1, tree.lazy[id])
		tree.lazy[id] = 0
	}
}

func min(a, b int) int {
	if a <= b {
		return a
	}
	return b
}

package main

import (
	. "fmt"
	"io"
	"os"
	"sort"
)

// github.com/EndlessCheng/codeforces-go
func CF1487E(_r io.Reader, out io.Writer) {
	_i, _n, buf := 0, 0, make([]byte, 1<<12)
	rc := func() byte {
		if _i == _n {
			_n, _ = _r.Read(buf)
			if _n == 0 {
				return 0
			}
			_i = 0
		}
		b := buf[_i]
		_i++
		return b
	}
	r := func() (x int) {
		b := rc()
		for ; '0' > b; b = rc() {
		}
		for ; '0' <= b; b = rc() {
			x = x*10 + int(b&15)
		}
		return
	}
	const inf int = 1e9
	type pair struct{ v, i int }

	n := [4]int{}
	for i := range n {
		n[i] = r()
	}
	a := [4][]pair{}
	for i := range a {
		a[i] = make([]pair, n[i])
		for j := range a[i] {
			a[i][j] = pair{r(), j}
		}
	}
	vis := make([]bool, 15e4)
	for i := 1; i < 4; i++ {
		pre, cur := a[i-1], a[i]
		sort.Slice(pre, func(i, j int) bool { return pre[i].v < pre[j].v })
		b := make([][]int, len(cur))
		for m := r(); m > 0; m-- {
			v, w := r()-1, r()-1
			b[w] = append(b[w], v)
		}
		for j, ps := range b {
			for _, p := range ps {
				vis[p] = true
			}
			mi := inf
			for _, p := range pre {
				if !vis[p.i] {
					mi = p.v
					break
				}
			}
			cur[j].v += mi
			for _, p := range ps {
				vis[p] = false
			}
		}
	}
	ans := inf
	for _, p := range a[3] {
		if p.v < ans {
			ans = p.v
		}
	}
	if ans == inf {
		ans = -1
	}
	Fprintln(out, ans)
}

func main() { CF1487E(os.Stdin, os.Stdout) }

package main

import (
	. "fmt"
	"io"
	"os"
	"runtime/debug"
	"sort"
)

// github.com/EndlessCheng/codeforces-go
func init() { debug.SetGCPercent(-1) }

func CF1487E(_r io.Reader, out io.Writer) {
	_i, _n, buf := 0, 0, make([]byte, 1<<12)
	rc := func() byte {
		if _i == _n {
			_n, _ = _r.Read(buf)
			if _n == 0 {
				return 0
			}
			_i = 0
		}
		b := buf[_i]
		_i++
		return b
	}
	r := func() (x int) {
		b := rc()
		for ; '0' > b; b = rc() {
		}
		for ; '0' <= b; b = rc() {
			x = x*10 + int(b&15)
		}
		return
	}
	type pair struct{ v, i int }

	n := [4]int{}
	for i := range n {
		n[i] = r()
	}
	a := [4][]pair{}
	for i := range a {
		a[i] = make([]pair, n[i])
		for j := range a[i] {
			a[i][j] = pair{r(), j}
		}
	}
	vis := make([]bool, 15e4)
	for i := 1; i < 4; i++ {
		pre, cur := a[i-1], a[i]
		sort.Slice(pre, func(i, j int) bool { return pre[i].v < pre[j].v })
		b := make([][]int, len(cur))
		for m := r(); m > 0; m-- {
			v, w := r()-1, r()-1
			b[w] = append(b[w], v)
		}
		for j, ps := range b {
			for _, p := range ps {
				vis[p] = true
			}
			mi := int(1e9)
			for _, p := range pre {
				if !vis[p.i] {
					mi = p.v
					break
				}
			}
			cur[j].v += mi
			for _, p := range ps {
				vis[p] = false
			}
		}
	}
	ans := int(1e9)
	for _, p := range a[3] {
		if p.v < ans {
			ans = p.v
		}
	}
	if ans == 1e9 {
		ans = -1
	}
	Fprintln(out, ans)
}

func main() { CF1487E(os.Stdin, os.Stdout) }

package main

import (
	. "fmt"
	"io"
	"os"
	"sort"
)

// github.com/EndlessCheng/codeforces-go
func CF1487E(_r io.Reader, out io.Writer) {
	_i, _n, buf := 0, 0, make([]byte, 1<<12)
	rc := func() byte {
		if _i == _n {
			_n, _ = _r.Read(buf)
			if _n == 0 {
				return 0
			}
			_i = 0
		}
		b := buf[_i]
		_i++
		return b
	}
	r := func() (x int) {
		b := rc()
		for ; '0' > b; b = rc() {
		}
		for ; '0' <= b; b = rc() {
			x = x*10 + int(b&15)
		}
		return
	}
	type pair struct{ v, i int }

	n := [4]int{}
	for i := range n {
		n[i] = r()
	}
	a := [4][]pair{}
	for i := range a {
		a[i] = make([]pair, n[i])
		for j := range a[i] {
			a[i][j] = pair{r(), j}
		}
	}
	vis := make([]bool, 15e4)
	for i := 1; i < 4; i++ {
		pre, cur := a[i-1], a[i]
		sort.Slice(pre, func(i, j int) bool { return pre[i].v < pre[j].v })
		b := make([][]int, len(cur))
		for m := r(); m > 0; m-- {
			v, w := r()-1, r()-1
			b[w] = append(b[w], v)
		}
		for j, ps := range b {
			for _, p := range ps {
				vis[p] = true
			}
			mi := int(1e9)
			for _, p := range pre {
				if !vis[p.i] {
					mi = p.v
					break
				}
			}
			cur[j].v += mi
			for _, p := range ps {
				vis[p] = false
			}
		}
	}
	ans := int(1e9)
	for _, p := range a[3] {
		if p.v < ans {
			ans = p.v
		}
	}
	if ans == 1e9 {
		ans = -1
	}
	Fprintln(out, ans)
}

func main() { CF1487E(os.Stdin, os.Stdout) }

package main

import (
	. "fmt"
	"io"
	"os"
	"sort"
)

// github.com/EndlessCheng/codeforces-go
func CF1487E(_r io.Reader, out io.Writer) {
	_i, _n, buf := 0, 0, make([]byte, 1<<12)
	rc := func() byte {
		if _i == _n {
			_n, _ = _r.Read(buf)
			if _n == 0 {
				return 0
			}
			_i = 0
		}
		b := buf[_i]
		_i++
		return b
	}
	r := func() (x int) {
		b := rc()
		for ; '0' > b; b = rc() {
		}
		for ; '0' <= b; b = rc() {
			x = x*10 + int(b&15)
		}
		return
	}
	type pair struct{ v, i int }

	n := [4]int{}
	for i := range n {
		n[i] = r()
	}
	a := [4][]pair{}
	for i := range a {
		a[i] = make([]pair, n[i])
		for j := range a[i] {
			a[i][j] = pair{r(), j}
		}
	}
	vis := make([]bool, 15e4)
	for i := 1; i < 4; i++ {
		pre := a[i-1]
		sort.Slice(pre, func(i, j int) bool { return pre[i].v < pre[j].v })
		b := make([][]int, len(a[i]))
		for m := r(); m > 0; m-- {
			v, w := r()-1, r()-1
			b[w] = append(b[w], v)
		}
		for j, ps := range b {
			for _, p := range ps {
				vis[p] = true
			}
			mi := int(1e9)
			for _, p := range a[i-1] {
				if !vis[p.i] {
					mi = p.v
					break
				}
			}
			a[i][j].v += mi
			for _, p := range ps {
				vis[p] = false
			}
		}
	}
	ans := int(1e9)
	for _, p := range a[3] {
		if p.v < ans {
			ans = p.v
		}
	}
	if ans == 1e9 {
		ans = -1
	}
	Fprintln(out, ans)
}

func main() { CF1487E(os.Stdin, os.Stdout) }

package main

import (
	"container/heap"
	. "fmt"
	"io"
	"os"
)

// github.com/EndlessCheng/codeforces-go
type pair struct{ v, i int }
type hp []pair

func (h hp) Len() int            { return len(h) }
func (h hp) Less(i, j int) bool  { return h[i].v < h[j].v }
func (h hp) Swap(i, j int)       { h[i], h[j] = h[j], h[i] }
func (h *hp) Push(v interface{}) { *h = append(*h, v.(pair)) }
func (h *hp) Pop() interface{}   { a := *h; v := a[len(a)-1]; *h = a[:len(a)-1]; return v }

func CF1487E(_r io.Reader, out io.Writer) {
	_i, _n, buf := 0, 0, make([]byte, 1<<12)
	rc := func() byte {
		if _i == _n {
			_n, _ = _r.Read(buf)
			if _n == 0 {
				return 0
			}
			_i = 0
		}
		b := buf[_i]
		_i++
		return b
	}
	r := func() (x int) {
		b := rc()
		for ; '0' > b; b = rc() {
		}
		for ; '0' <= b; b = rc() {
			x = x*10 + int(b&15)
		}
		return
	}

	n := [4]int{}
	for i := range n {
		n[i] = r()
	}
	a := [4][]int{}
	for i := range a {
		a[i] = make([]int, n[i])
		for j := range a[i] {
			a[i][j] = r()
		}
	}
	vis := make([]int8, 15e4)
	for i := 1; i < 4; i++ {
		h := hp{}
		for j, v := range a[i-1] {
			if v < 1e9 {
				h = append(h, pair{v, j})
			}
		}
		heap.Init(&h)
		b := make([][]int, len(a[i]))
		for m := r(); m > 0; m-- {
			v, w := r()-1, r()-1
			b[w] = append(b[w], v)
		}
		for j, ps := range b {
			for _, p := range ps {
				vis[p] = 1
			}
			mi := int(1e9)
			for len(h) > 0 {
				if vis[h[0].i] == 0 {
					mi = h[0].v
					break
				}
				vis[h[0].i] = -1
				heap.Pop(&h)
			}
			a[i][j] += mi
			for _, p := range ps {
				if vis[p] < 0 {
					heap.Push(&h, pair{a[i-1][p], p})
				}
				vis[p] = 0
			}
		}
	}
	ans := int(1e9)
	for _, v := range a[3] {
		if v < ans {
			ans = v
		}
	}
	if ans == 1e9 {
		ans = -1
	}
	Fprintln(out, ans)
}

func main() { CF1487E(os.Stdin, os.Stdout) }

package main

import (
	. "fmt"
	"io"
	"os"
	"runtime/debug"
)

// github.com/EndlessCheng/codeforces-go
func init() { debug.SetGCPercent(-1) }

type node struct {
	lr       [2]*node
	priority uint
	key, cnt int
}

func (o *node) cmp(b int) int {
	switch {
	case b < o.key:
		return 0
	case b > o.key:
		return 1
	default:
		return -1
	}
}

func (o *node) rotate(d int) *node {
	x := o.lr[d^1]
	o.lr[d^1] = x.lr[d]
	x.lr[d] = o
	return x
}

type treap struct {
	rd   uint
	root *node
}

func (t *treap) fastRand() uint {
	t.rd ^= t.rd << 13
	t.rd ^= t.rd >> 17
	t.rd ^= t.rd << 5
	return t.rd
}

func (t *treap) _put(o *node, key int) *node {
	if o == nil {
		return &node{priority: t.fastRand(), key: key, cnt: 1}
	}
	if d := o.cmp(key); d >= 0 {
		o.lr[d] = t._put(o.lr[d], key)
		if o.lr[d].priority > o.priority {
			o = o.rotate(d ^ 1)
		}
	} else {
		o.cnt++
	}
	return o
}

func (t *treap) put(key int) { t.root = t._put(t.root, key) }

func (t *treap) _delete(o *node, key int) *node {
	if o == nil {
		return nil
	}
	if d := o.cmp(key); d >= 0 {
		o.lr[d] = t._delete(o.lr[d], key)
	} else {
		if o.cnt > 1 {
			o.cnt--
		} else {
			if o.lr[1] == nil {
				return o.lr[0]
			}
			if o.lr[0] == nil {
				return o.lr[1]
			}
			d = 0
			if o.lr[0].priority > o.lr[1].priority {
				d = 1
			}
			o = o.rotate(d)
			o.lr[d] = t._delete(o.lr[d], key)
		}
	}
	return o
}

func (t *treap) delete(key int) { t.root = t._delete(t.root, key) }

func (t *treap) min() int {
	mi := int(1e9)
	for o := t.root; o != nil; o = o.lr[0] {
		mi = o.key
	}
	return mi
}

func CF1487E(_r io.Reader, out io.Writer) {
	_i, _n, buf := 0, 0, make([]byte, 1<<12)
	rc := func() byte {
		if _i == _n {
			_n, _ = _r.Read(buf)
			if _n == 0 {
				return 0
			}
			_i = 0
		}
		b := buf[_i]
		_i++
		return b
	}
	r := func() (x int) {
		b := rc()
		for ; '0' > b; b = rc() {
		}
		for ; '0' <= b; b = rc() {
			x = x*10 + int(b&15)
		}
		return
	}

	n := [4]int{}
	for i := range n {
		n[i] = r()
	}
	a := [4][]int{}
	for i := range a {
		a[i] = make([]int, n[i])
		for j := range a[i] {
			a[i][j] = r()
		}
	}
	for i := 1; i < 4; i++ {
		t := &treap{rd: 1}
		for _, v := range a[i-1] {
			if v < 1e9 {
				t.put(v)
			}
		}
		b := make([][]int, len(a[i]))
		for m := r(); m > 0; m-- {
			v, w := r()-1, r()-1
			b[w] = append(b[w], v)
		}
		for j, ps := range b {
			for _, p := range ps {
				t.delete(a[i-1][p])
			}
			a[i][j] += t.min()
			for _, p := range ps {
				t.put(a[i-1][p])
			}
		}
	}
	ans := int(1e9)
	for _, v := range a[3] {
		if v < ans {
			ans = v
		}
	}
	if ans == 1e9 {
		ans = -1
	}
	Fprintln(out, ans)
}

func main() { CF1487E(os.Stdin, os.Stdout) }

package main

import (
	"bufio"
	. "fmt"
	"io"
	"os"
	"runtime/debug"
)

// github.com/EndlessCheng/codeforces-go
func init() { debug.SetGCPercent(-1) }

type node struct {
	lr       [2]*node
	priority uint
	key, cnt int
}

func (o *node) cmp(b int) int {
	switch {
	case b < o.key:
		return 0
	case b > o.key:
		return 1
	default:
		return -1
	}
}

func (o *node) rotate(d int) *node {
	x := o.lr[d^1]
	o.lr[d^1] = x.lr[d]
	x.lr[d] = o
	return x
}

type treap struct {
	rd   uint
	root *node
}

func (t *treap) fastRand() uint {
	t.rd ^= t.rd << 13
	t.rd ^= t.rd >> 17
	t.rd ^= t.rd << 5
	return t.rd
}

func (t *treap) _put(o *node, key int) *node {
	if o == nil {
		return &node{priority: t.fastRand(), key: key, cnt: 1}
	}
	if d := o.cmp(key); d >= 0 {
		o.lr[d] = t._put(o.lr[d], key)
		if o.lr[d].priority > o.priority {
			o = o.rotate(d ^ 1)
		}
	} else {
		o.cnt++
	}
	return o
}

func (t *treap) put(key int) { t.root = t._put(t.root, key) }

func (t *treap) _delete(o *node, key int) *node {
	if o == nil {
		return nil
	}
	if d := o.cmp(key); d >= 0 {
		o.lr[d] = t._delete(o.lr[d], key)
	} else {
		if o.cnt > 1 {
			o.cnt--
		} else {
			if o.lr[1] == nil {
				return o.lr[0]
			}
			if o.lr[0] == nil {
				return o.lr[1]
			}
			d = 0
			if o.lr[0].priority > o.lr[1].priority {
				d = 1
			}
			o = o.rotate(d)
			o.lr[d] = t._delete(o.lr[d], key)
		}
	}
	return o
}

func (t *treap) delete(key int) { t.root = t._delete(t.root, key) }

func (t *treap) min() int {
	mi := int(1e9)
	for o := t.root; o != nil; o = o.lr[0] {
		mi = o.key
	}
	return mi
}

func CF1487E(_r io.Reader, _w io.Writer) {
	in := bufio.NewReader(_r)
	out := bufio.NewWriter(_w)
	defer out.Flush()

	var m, v, w int
	n := [4]int{}
	Fscan(in, &n[0], &n[1], &n[2], &n[3])
	a := [4][]int{}
	for i := range a {
		a[i] = make([]int, n[i])
		for j := range a[i] {
			Fscan(in, &a[i][j])
		}
	}
	for i := 1; i < 4; i++ {
		t := &treap{rd: 1}
		for _, v := range a[i-1] {
			if v < 1e9 {
				t.put(v)
			}
		}
		b := make([][]int, len(a[i]))
		for Fscan(in, &m); m > 0; m-- {
			Fscan(in, &v, &w)
			b[w-1] = append(b[w-1], v-1)
		}
		for j, ps := range b {
			for _, p := range ps {
				t.delete(a[i-1][p])
			}
			a[i][j] += t.min()
			for _, p := range ps {
				t.put(a[i-1][p])
			}
		}
	}
	ans := int(1e9)
	for _, v := range a[3] {
		if v < ans {
			ans = v
		}
	}
	if ans == 1e9 {
		ans = -1
	}
	Fprintln(out, ans)
}

func main() { CF1487E(os.Stdin, os.Stdout) }

package main

import (
	"bufio"
	. "fmt"
	"io"
	"os"
)

// github.com/EndlessCheng/codeforces-go
type node struct {
	lr       [2]*node
	priority uint
	key, cnt int
}

func (o *node) cmp(b int) int {
	switch {
	case b < o.key:
		return 0
	case b > o.key:
		return 1
	default:
		return -1
	}
}

func (o *node) rotate(d int) *node {
	x := o.lr[d^1]
	o.lr[d^1] = x.lr[d]
	x.lr[d] = o
	return x
}

type treap struct {
	rd   uint
	root *node
}

func (t *treap) fastRand() uint {
	t.rd ^= t.rd << 13
	t.rd ^= t.rd >> 17
	t.rd ^= t.rd << 5
	return t.rd
}

func (t *treap) _put(o *node, key int) *node {
	if o == nil {
		return &node{priority: t.fastRand(), key: key, cnt: 1}
	}
	if d := o.cmp(key); d >= 0 {
		o.lr[d] = t._put(o.lr[d], key)
		if o.lr[d].priority > o.priority {
			o = o.rotate(d ^ 1)
		}
	} else {
		o.cnt++
	}
	return o
}

func (t *treap) put(key int) { t.root = t._put(t.root, key) }

func (t *treap) _delete(o *node, key int) *node {
	if o == nil {
		return nil
	}
	if d := o.cmp(key); d >= 0 {
		o.lr[d] = t._delete(o.lr[d], key)
	} else {
		if o.cnt > 1 {
			o.cnt--
		} else {
			if o.lr[1] == nil {
				return o.lr[0]
			}
			if o.lr[0] == nil {
				return o.lr[1]
			}
			d = 0
			if o.lr[0].priority > o.lr[1].priority {
				d = 1
			}
			o = o.rotate(d)
			o.lr[d] = t._delete(o.lr[d], key)
		}
	}
	return o
}

func (t *treap) delete(key int) { t.root = t._delete(t.root, key) }

func (t *treap) min() int {
	mi := int(1e9)
	for o := t.root; o != nil; o = o.lr[0] {
		mi = o.key
	}
	return mi
}

func CF1487E(_r io.Reader, _w io.Writer) {
	in := bufio.NewReader(_r)
	out := bufio.NewWriter(_w)
	defer out.Flush()

	var m, v, w int
	n := [4]int{}
	Fscan(in, &n[0], &n[1], &n[2], &n[3])
	a := [4][]int{}
	for i := range a {
		a[i] = make([]int, n[i])
		for j := range a[i] {
			Fscan(in, &a[i][j])
		}
	}
	for i := 1; i < 4; i++ {
		t := &treap{rd: 1}
		for _, v := range a[i-1] {
			if v < 1e9 {
				t.put(v)
			}
		}
		b := make([][]int, len(a[i]))
		for Fscan(in, &m); m > 0; m-- {
			Fscan(in, &v, &w)
			b[w-1] = append(b[w-1], v-1)
		}
		for j, ps := range b {
			for _, p := range ps {
				t.delete(a[i-1][p])
			}
			a[i][j] += t.min()
			for _, p := range ps {
				t.put(a[i-1][p])
			}
		}
	}
	ans := int(1e9)
	for _, v := range a[3] {
		if v < ans {
			ans = v
		}
	}
	if ans == 1e9 {
		ans = -1
	}
	Fprintln(out, ans)
}

func main() { CF1487E(os.Stdin, os.Stdout) }

package main

import (
	"bufio"
	"fmt"
	"os"
	"sort"
)

const inf int64 = 1 << 60

func solveForCurrentAndPrevious(curr, prev []int64, adj [][]int) {
	seg := newSegtree(prev)

	for i := range curr {
		ans := inf

		for j := 1; j < len(adj[i]); j++ {
			prevIdx, currIdx := adj[i][j-1], adj[i][j]
			if prevIdx+1 > currIdx-1 {
				continue
			}
			ans = min(ans, seg.getMin(0, prevIdx+1, currIdx-1))
		}

		if ans != inf {
			curr[i] += ans
		} else {
			curr[i] = inf
		}
	}
}

func solveE(a [4][]int64, notok [4][][]int) {
	for i := 1; i < 4; i++ {
		solveForCurrentAndPrevious(a[i], a[i-1], notok[i])
	}

	ans := min(a[3]...)
	if ans == inf {
		ans = -1
	}
	printf("%d", ans)
}

func main() {
	defer writer.Flush()
	//redirectInputToFile(reader, "input.txt")

	T := 1
	// scan(&T)

	for t := 0; t < T; t++ {
		var n [4]int
		for i := range n {
			scan(&n[i])
		}

		var a [4][]int64
		for i := range n {
			a[i] = make([]int64, n[i])
			for j := range a[i] {
				scan(&a[i][j])
			}
		}

		var m [4]int
		var notok [4][][]int
		for i := 1; i < 4; i++ {
			notok[i] = make([][]int, n[i])

			scan(&m[i])
			for j := 0; j < m[i]; j++ {
				u, v := 0, 0
				scan(&u, &v)
				notok[i][v-1] = append(notok[i][v-1], u-1)
			}

			for j := range notok[i] {
				notok[i][j] = append(notok[i][j], -1, n[i-1])
				arr := notok[i][j]
				sort.Slice(arr, func(i, j int) bool { return arr[i] < arr[j] })
			}
		}

		solveE(a, notok)
	}
}

var reader *bufio.Reader = bufio.NewReader(os.Stdin)
var writer *bufio.Writer = bufio.NewWriter(os.Stdout)

func scan(a ...interface{})             { fmt.Fscan(reader, a...) }
func printf(f string, a ...interface{}) { fmt.Fprintf(writer, f, a...) }

func redirectInputToFile(r *bufio.Reader, fp string) {
	f, err := os.Open(fp)
	if err != nil {
		panic(err)
	}
	r.Reset(f)
}

// ------------------

type segtree []*segtreenode

type segtreenode struct {
	node, l, r int
	segtreedata
}

type segtreedata struct {
	min int64
}

func newSegtree(v []int64) *segtree {
	tr := make(segtree, 4*len(v))
	tr.build(0, v, 0, len(v)-1)
	return &tr
}

func (tree segtree) build(node int, v []int64, l, r int) {
	tree[node] = &segtreenode{
		node: node, l: l, r: r,
	}

	if l == r {
		tree[node].min = v[l]
		return
	}

	m := l + (r-l)/2
	tree.build(2*node+1, v, l, m)
	tree.build(2*node+2, v, m+1, r)

	tree[node].min = min(tree[2*node+1].min, tree[2*node+2].min)
}

func (tree segtree) getMin(node, l, r int) int64 {
	if l > r {
		return inf
	}

	nl, nr := tree[node].l, tree[node].r

	if r < nl || nr < l {
		return inf
	}

	if l <= nl && nr <= r {
		return tree[node].min
	}

	return min(
		tree.getMin(2*node+1, l, r),
		tree.getMin(2*node+2, l, r),
	)
}

func min(nums ...int64) int64 {
	mn := nums[0]
	for _, x := range nums {
		if mn > x {
			mn = x
		}
	}
	return mn
}

package main

import (
	"container/heap"
	"fmt"
	"log"
	"os"
	"strings"
)

type bufferedReader struct {
	buf     [4096]byte
	ptr, sz int
	eof     bool
	ended   bool
	in      *os.File
}

func newReader(in *os.File) bufferedReader {
	var tmp [4096]byte
	return bufferedReader{tmp, 0, 0, false, false, in}
}

func (r *bufferedReader) isEof() bool {
	return r.eof
}

func (r *bufferedReader) load() {
	if r.ended {
		r.eof = true
		return
	}
	sz, err := r.in.Read(r.buf[:])
	r.sz = sz
	if sz < 4096 {
		r.ended = true
	}
	if err != nil {
		log.Fatal(err)
	}
	r.ptr = 0
}

func (r *bufferedReader) getChar() byte {
	if r.ptr == r.sz && !r.eof {
		r.load()
	}
	if r.ptr == r.sz || r.eof {
		r.eof = true
		return 0
	}
	r.ptr += 1
	return r.buf[r.ptr-1]
}

func (r *bufferedReader) skipNonIntChars() {
	for {
		c := r.getChar()
		if r.eof {
			break
		}
		if (c >= 48 && c <= 57) || (c == 45) {
			r.ptr -= 1
			break
		}
	}
}

func (r *bufferedReader) skipWhitespace() {
	for {
		c := r.getChar()
		if r.eof {
			break
		}
		if c != ' ' && c != '\n' && c != '\t' && c != '\r' {
			r.ptr -= 1
			break
		}
	}
}

func (r *bufferedReader) readInt() int {
	r.skipNonIntChars()
	var ans int = 0
	var neg bool = false
	fst := r.getChar()
	if fst == 45 {
		neg = true
	} else {
		ans = int(fst) - 48
	}
	for {
		c := r.getChar()
		if r.eof {
			break
		}
		if c >= 48 && c <= 57 {
			ans = ans*10 + int(c-48)
		} else {
			r.ptr -= 1
			break
		}
	}
	if neg {
		ans = -ans
	}
	return ans
}

func (r *bufferedReader) readString() string {
	r.skipWhitespace()
	sz := 0
	capacity := 2
	s := make([]byte, 2)
	for {
		c := r.getChar()
		if r.eof {
			break
		}
		if c == ' ' || c == '\n' || c == '\t' || c == '\r' {
			r.ptr--
			break
		}
		if sz == capacity {
			capacity <<= 1
			s1 := make([]byte, capacity)
			for i := 0; i < sz; i++ {
				s1[i] = s[i]
			}
			s = s1
		}
		s[sz] = c
		sz++
	}
	return string(s[:sz])
}

type Item struct {
	value    int
	priority int
	index    int
}

type PriorityQueue []*Item

func (pq PriorityQueue) Len() int { return len(pq) }

func (pq PriorityQueue) Less(i, j int) bool {
	return pq[i].priority < pq[j].priority
}

func (pq PriorityQueue) Swap(i, j int) {
	pq[i], pq[j] = pq[j], pq[i]
	pq[i].index = i
	pq[j].index = j
}

func (pq *PriorityQueue) Push(x interface{}) {
	n := len(*pq)
	item := x.(*Item)
	item.index = n
	*pq = append(*pq, item)
}

func (pq *PriorityQueue) Pop() interface{} {
	old := *pq
	n := len(old)
	item := old[n-1]
	old[n-1] = nil  // avoid memory leak
	item.index = -1 // for safety
	*pq = old[0 : n-1]
	return item
}

const inf int = 1000000000

func main() {
	var in bufferedReader
	hostname, err := os.Hostname()
	if err != nil {
		log.Fatal(err)
	}
	if strings.HasSuffix(hostname, "lenovo") {
		file, _ := os.Open("input.txt")
		in = newReader(file)
	} else {
		in = newReader(os.Stdin)
	}
	var n [4]int
	for i := 0; i < 4; i++ {
		n[i] = in.readInt()
	}
	a := make([][]int, 4)
	fuck := make([][][]int, 4)
	for i := 0; i < 4; i++ {
		a[i] = make([]int, n[i])
		fuck[i] = make([][]int, n[i])
		for j := 0; j < n[i]; j++ {
			a[i][j] = in.readInt()
			fuck[i][j] = make([]int, 0)
		}
	}
	for i := 0; i < 3; i++ {
		sz := in.readInt()
		for j := 0; j < sz; j++ {
			v := in.readInt()
			u := in.readInt()
			v--
			u--
			fuck[i][v] = append(fuck[i][v], u)
		}
	}
	dp := make([][]int, 4)
	for i := 0; i < 4; i++ {
		dp[i] = make([]int, n[i])
		for j := 0; j < n[i]; j++ {
			dp[i][j] = inf
		}
	}
	for j := 0; j < n[3]; j++ {
		dp[3][j] = a[3][j]
	}
	bad := make([]int, 200055)
	for c := 2; c >= 0; c-- {
		h := make(PriorityQueue, n[c+1])
		for j := 0; j < n[c+1]; j++ {
			h[j] = &Item{value: j, priority: dp[c+1][j], index: j}
		}
		heap.Init(&h)
		for i := 0; i < n[c]; i++ {
			for _, j := range fuck[c][i] {
				bad[j] = 1
			}
			for h.Len() > 0 {
				item := heap.Pop(&h).(*Item)
				if bad[item.value] == 1 {
					bad[item.value] = -1
				} else {
					curr := item.priority + a[c][i]
					if dp[c][i] > curr {
						dp[c][i] = curr
					}
					heap.Push(&h, item)
					break
				}
			}
			for _, j := range fuck[c][i] {
				if bad[j] == -1 {
					item := &Item{value: j, priority: dp[c+1][j]}
					heap.Push(&h, item)
				}
				bad[j] = 0
			}
		}
	}
	mx := inf
	for i := 0; i < n[0]; i++ {
		if mx > dp[0][i] {
			mx = dp[0][i]
		}
	}
	if mx == inf {
		fmt.Printf("-1\n")
	} else {
		fmt.Printf("%d\n", mx)
	}
}

package main

import (
	"bufio"
	"fmt"
	"os"
	"sort"
)

func main() {
	reader := bufio.NewReader(os.Stdin)

	first := readNNums(reader, 4)
	A := readNNums(reader, first[0])
	B := readNNums(reader, first[1])
	C := readNNums(reader, first[2])
	D := readNNums(reader, first[3])

	m := readNum(reader)
	X := make([][]int, m)
	for i := 0; i < m; i++ {
		X[i] = readNNums(reader, 2)
	}
	m = readNum(reader)
	Y := make([][]int, m)
	for i := 0; i < m; i++ {
		Y[i] = readNNums(reader, 2)
	}
	m = readNum(reader)
	Z := make([][]int, m)
	for i := 0; i < m; i++ {
		Z[i] = readNNums(reader, 2)
	}
	fmt.Println(solve1(A, B, C, D, X, Y, Z))
}

func readInt(bytes []byte, from int, val *int) int {
	i := from
	sign := 1
	if bytes[i] == '-' {
		sign = -1
		i++
	}
	tmp := 0
	for i < len(bytes) && bytes[i] >= '0' && bytes[i] <= '9' {
		tmp = tmp*10 + int(bytes[i]-'0')
		i++
	}
	*val = tmp * sign
	return i
}

func readNum(reader *bufio.Reader) (a int) {
	bs, _ := reader.ReadBytes('\n')
	readInt(bs, 0, &a)
	return
}

func readTwoNums(reader *bufio.Reader) (a int, b int) {
	res := readNNums(reader, 2)
	a, b = res[0], res[1]
	return
}

func readThreeNums(reader *bufio.Reader) (a int, b int, c int) {
	res := readNNums(reader, 3)
	a, b, c = res[0], res[1], res[2]
	return
}

func readNNums(reader *bufio.Reader, n int) []int {
	res := make([]int, n)
	x := 0
	bs, _ := reader.ReadBytes('\n')
	for i := 0; i < n; i++ {
		for x < len(bs) && (bs[x] < '0' || bs[x] > '9') && bs[x] != '-' {
			x++
		}
		x = readInt(bs, x, &res[i])
	}
	return res
}

func readUint64(bytes []byte, from int, val *uint64) int {
	i := from

	var tmp uint64
	for i < len(bytes) && bytes[i] >= '0' && bytes[i] <= '9' {
		tmp = tmp*10 + uint64(bytes[i]-'0')
		i++
	}
	*val = tmp

	return i
}

const MAX_N = 150010
const INF = 400000010

func solve(A, B, C, D []int, X, Y, Z [][]int) int {

	proc := func(a, b []int, c [][]int) []int {
		n1 := len(a)
		n2 := len(b)
		m := len(c)
		g := NewGraph(n1+n2, m)

		for _, x := range c {
			u, v := x[0], x[1]
			u--
			v--
			g.AddEdge(u, v+n1)
		}
		var set *Node
		for i := 0; i < n2; i++ {
			if b[i] < INF {
				set = Insert(set, b[i])
			}
		}
		res := make([]int, n1)
		for u := 0; u < n1; u++ {
			for i := g.nodes[u]; i > 0; i = g.next[i] {
				v := g.to[i] - n1
				if b[v] < INF {
					set = Delete(set, b[v])
				}
			}
			res[u] = INF
			if set != nil {
				res[u] = MinValueNode(set).key + a[u]
			}

			for i := g.nodes[u]; i > 0; i = g.next[i] {
				v := g.to[i] - n1
				if b[v] < INF {
					set = Insert(set, b[v])
				}
			}
		}
		return res
	}

	R := proc(C, D, Z)
	R = proc(B, R, Y)
	R = proc(A, R, X)
	var best int = INF
	for i := 0; i < len(R); i++ {
		best = min(best, R[i])
	}
	if best >= INF {
		return -1
	}
	return best
}

type Graph struct {
	nodes []int
	next  []int
	to    []int
	cur   int
}

func NewGraph(n int, e int) *Graph {
	nodes := make([]int, n)
	next := make([]int, e+3)
	to := make([]int, e+3)
	return &Graph{nodes, next, to, 0}
}

func (g *Graph) AddEdge(u, v int) {
	g.cur++
	g.next[g.cur] = g.nodes[u]
	g.nodes[u] = g.cur
	g.to[g.cur] = v
}

/**
* this is a AVL tree
 */
type Node struct {
	key         int
	height      int
	cnt         int
	left, right *Node
}

func (node *Node) Height() int {
	if node == nil {
		return 0
	}
	return node.height
}

func max(a, b int) int {
	if a >= b {
		return a
	}
	return b
}

func NewNode(key int) *Node {
	node := new(Node)
	node.key = key
	node.height = 1
	node.cnt = 1
	return node
}

func rightRotate(y *Node) *Node {
	x := y.left

	t2 := x.right

	x.right = y
	y.left = t2
	y.height = max(y.left.Height(), y.right.Height()) + 1
	x.height = max(x.left.Height(), x.right.Height()) + 1

	return x
}

func leftRotate(x *Node) *Node {
	y := x.right
	t2 := y.left

	y.left = x
	x.right = t2

	x.height = max(x.left.Height(), x.right.Height()) + 1
	y.height = max(y.left.Height(), y.right.Height()) + 1

	return y
}

func (node *Node) GetBalance() int {
	if node == nil {
		return 0
	}
	return node.left.Height() - node.right.Height()
}

func Insert(node *Node, key int) *Node {
	if node == nil {
		return NewNode(key)
	}
	if node.key == key {
		node.cnt++
		return node
	}

	if node.key > key {
		node.left = Insert(node.left, key)
	} else {
		node.right = Insert(node.right, key)
	}

	node.height = max(node.left.Height(), node.right.Height()) + 1
	balance := node.GetBalance()

	if balance > 1 && key < node.left.key {
		return rightRotate(node)
	}

	if balance < -1 && key > node.right.key {
		return leftRotate(node)
	}

	if balance > 1 && key > node.left.key {
		node.left = leftRotate(node.left)
		return rightRotate(node)
	}

	if balance < -1 && key < node.right.key {
		node.right = rightRotate(node.right)
		return leftRotate(node)
	}

	return node
}

func MinValueNode(root *Node) *Node {
	cur := root

	for cur.left != nil {
		cur = cur.left
	}

	return cur
}

func (root *Node) MinValue() int {
	if root == nil {
		return 0
	}
	node := MinValueNode(root)

	return node.key
}

func Delete(root *Node, key int) *Node {
	if root == nil {
		return nil
	}

	if key < root.key {
		root.left = Delete(root.left, key)
	} else if key > root.key {
		root.right = Delete(root.right, key)
	} else {
		root.cnt--
		if root.cnt > 0 {
			return root
		}
		if root.left == nil || root.right == nil {
			tmp := root.left
			if root.left == nil {
				tmp = root.right
			}
			root = tmp
		} else {
			tmp := MinValueNode(root.right)

			root.key = tmp.key
			root.cnt = tmp.cnt
			// make sure tmp node deleted after call delete on root.right
			tmp.cnt = 1
			root.right = Delete(root.right, tmp.key)
		}
	}

	if root == nil {
		return root
	}

	root.height = max(root.left.Height(), root.right.Height()) + 1
	balance := root.GetBalance()

	if balance > 1 && root.left.GetBalance() >= 0 {
		return rightRotate(root)
	}

	if balance > 1 && root.left.GetBalance() < 0 {
		root.left = leftRotate(root.left)
		return rightRotate(root)
	}

	if balance < -1 && root.right.GetBalance() <= 0 {
		return leftRotate(root)
	}

	if balance < -1 && root.right.GetBalance() > 0 {
		root.right = rightRotate(root.right)
		return leftRotate(root)
	}

	return root
}

func solve1(A, B, C, D []int, X, Y, Z [][]int) int {
	R := process(C, D, Z)
	R = process(B, R, Y)
	R = process(A, R, X)
	var best int = INF
	for i := 0; i < len(R); i++ {
		best = min(best, R[i])
	}
	if best >= INF {
		return -1
	}
	return best
}

func process(A, B []int, X [][]int) []int {
	n1 := len(A)
	n2 := len(B)
	cnt := make([]int, n2)
	for _, x := range X {
		cnt[x[1]-1]++
	}

	pref := make([][]int, n2)
	for i := 0; i < n2; i++ {
		pref[i] = make([]int, 0, cnt[i])
	}

	sort.Slice(X, func(i, j int) bool {
		return X[i][0] < X[j][0]
	})

	for _, x := range X {
		a, b := x[0], x[1]
		a--
		b--
		if B[b] >= INF {
			continue
		}
		pref[b] = append(pref[b], a)
	}

	tree := NewSegTree(n1)
	tree.Update(0, n1-1, INF)

	for i := 0; i < n2; i++ {
		if B[i] >= INF {
			continue
		}
		cur := pref[i]
		//sort.Ints(cur)
		var p int
		for j := 0; j < len(cur); j++ {
			if cur[j] > p {
				tree.Update(p, cur[j]-1, B[i])
			}
			p = cur[j] + 1
		}
		if p < n1 {
			tree.Update(p, n1-1, B[i])
		}
	}

	res := make([]int, n1)

	for i := 0; i < n1; i++ {
		tmp := tree.Query(i, i)
		if tmp < INF {
			res[i] = tmp + A[i]
		} else {
			res[i] = INF
		}
	}
	return res
}

type SegTree struct {
	arr  []int
	lazy []int
	n    int
}

func NewSegTree(n int) *SegTree {
	arr := make([]int, 4*n)
	lazy := make([]int, 4*n)
	for i := 0; i < len(arr); i++ {
		arr[i] = INF + 1
	}
	return &SegTree{arr, lazy, n}
}

func (tree *SegTree) Update(L, R int, V int) {
	var loop func(i int, l, r int)
	loop = func(i int, l, r int) {
		if r < L || R < l {
			return
		}
		if L <= l && r <= R {
			tree.change(i, V)
			return
		}
		tree.push(i)
		mid := (l + r) / 2
		loop(2*i, l, mid)
		loop(2*i+1, mid+1, r)
		tree.arr[i] = min(tree.arr[2*i], tree.arr[2*i+1])
	}
	loop(1, 0, tree.n-1)
}

func (tree *SegTree) Query(L, R int) int {
	var loop func(i int, l, r int) int
	loop = func(i int, l, r int) int {
		if r < L || R < l {
			return INF
		}
		if L <= l && r <= R {
			return tree.arr[i]
		}

		tree.push(i)

		mid := (l + r) / 2
		a := loop(2*i, l, mid)
		b := loop(2*i+1, mid+1, r)
		return min(a, b)
	}
	return loop(1, 0, tree.n-1)
}

func (tree *SegTree) change(id int, v int) {
	if tree.arr[id] > v {
		tree.arr[id] = v
		tree.lazy[id] = v
	}
}

func (tree *SegTree) push(id int) {
	if tree.lazy[id] > 0 {
		tree.change(id*2, tree.lazy[id])
		tree.change(id*2+1, tree.lazy[id])
		tree.lazy[id] = 0
	}
}

func min(a, b int) int {
	if a <= b {
		return a
	}
	return b
}

package main

import (
	"bufio"
	"fmt"
	"os"
	"sort"
)

func main() {
	reader := bufio.NewReader(os.Stdin)

	first := readNNums(reader, 4)
	A := readNNums(reader, first[0])
	B := readNNums(reader, first[1])
	C := readNNums(reader, first[2])
	D := readNNums(reader, first[3])

	m := readNum(reader)
	X := make([][]int, m)
	for i := 0; i < m; i++ {
		X[i] = readNNums(reader, 2)
	}
	m = readNum(reader)
	Y := make([][]int, m)
	for i := 0; i < m; i++ {
		Y[i] = readNNums(reader, 2)
	}
	m = readNum(reader)
	Z := make([][]int, m)
	for i := 0; i < m; i++ {
		Z[i] = readNNums(reader, 2)
	}
	fmt.Println(solve1(A, B, C, D, X, Y, Z))
}

func readInt(bytes []byte, from int, val *int) int {
	i := from
	sign := 1
	if bytes[i] == '-' {
		sign = -1
		i++
	}
	tmp := 0
	for i < len(bytes) && bytes[i] >= '0' && bytes[i] <= '9' {
		tmp = tmp*10 + int(bytes[i]-'0')
		i++
	}
	*val = tmp * sign
	return i
}

func readNum(reader *bufio.Reader) (a int) {
	bs, _ := reader.ReadBytes('\n')
	readInt(bs, 0, &a)
	return
}

func readTwoNums(reader *bufio.Reader) (a int, b int) {
	res := readNNums(reader, 2)
	a, b = res[0], res[1]
	return
}

func readThreeNums(reader *bufio.Reader) (a int, b int, c int) {
	res := readNNums(reader, 3)
	a, b, c = res[0], res[1], res[2]
	return
}

func readNNums(reader *bufio.Reader, n int) []int {
	res := make([]int, n)
	x := 0
	bs, _ := reader.ReadBytes('\n')
	for i := 0; i < n; i++ {
		for x < len(bs) && (bs[x] < '0' || bs[x] > '9') && bs[x] != '-' {
			x++
		}
		x = readInt(bs, x, &res[i])
	}
	return res
}

func readUint64(bytes []byte, from int, val *uint64) int {
	i := from

	var tmp uint64
	for i < len(bytes) && bytes[i] >= '0' && bytes[i] <= '9' {
		tmp = tmp*10 + uint64(bytes[i]-'0')
		i++
	}
	*val = tmp

	return i
}

const MAX_N = 150010
const INF = 400000010

func solve(A, B, C, D []int, X, Y, Z [][]int) int {

	proc := func(a, b []int, c [][]int) []int {
		n1 := len(a)
		n2 := len(b)
		m := len(c)
		g := NewGraph(n1+n2, m)

		for _, x := range c {
			u, v := x[0], x[1]
			u--
			v--
			g.AddEdge(u, v+n1)
		}
		var set *Node
		for i := 0; i < n2; i++ {
			if b[i] < INF {
				set = Insert(set, b[i])
			}
		}
		res := make([]int, n1)
		for u := 0; u < n1; u++ {
			for i := g.nodes[u]; i > 0; i = g.next[i] {
				v := g.to[i] - n1
				if b[v] < INF {
					set = Delete(set, b[v])
				}
			}
			res[u] = INF
			if set != nil {
				res[u] = MinValueNode(set).key + a[u]
			}

			for i := g.nodes[u]; i > 0; i = g.next[i] {
				v := g.to[i] - n1
				if b[v] < INF {
					set = Insert(set, b[v])
				}
			}
		}
		return res
	}

	R := proc(C, D, Z)
	R = proc(B, R, Y)
	R = proc(A, R, X)
	var best int = INF
	for i := 0; i < len(R); i++ {
		best = min(best, R[i])
	}
	if best >= INF {
		return -1
	}
	return best
}

type Graph struct {
	nodes []int
	next  []int
	to    []int
	cur   int
}

func NewGraph(n int, e int) *Graph {
	nodes := make([]int, n)
	next := make([]int, e+3)
	to := make([]int, e+3)
	return &Graph{nodes, next, to, 0}
}

func (g *Graph) AddEdge(u, v int) {
	g.cur++
	g.next[g.cur] = g.nodes[u]
	g.nodes[u] = g.cur
	g.to[g.cur] = v
}

/**
* this is a AVL tree
 */
type Node struct {
	key         int
	height      int
	cnt         int
	left, right *Node
}

func (node *Node) Height() int {
	if node == nil {
		return 0
	}
	return node.height
}

func max(a, b int) int {
	if a >= b {
		return a
	}
	return b
}

func NewNode(key int) *Node {
	node := new(Node)
	node.key = key
	node.height = 1
	node.cnt = 1
	return node
}

func rightRotate(y *Node) *Node {
	x := y.left

	t2 := x.right

	x.right = y
	y.left = t2
	y.height = max(y.left.Height(), y.right.Height()) + 1
	x.height = max(x.left.Height(), x.right.Height()) + 1

	return x
}

func leftRotate(x *Node) *Node {
	y := x.right
	t2 := y.left

	y.left = x
	x.right = t2

	x.height = max(x.left.Height(), x.right.Height()) + 1
	y.height = max(y.left.Height(), y.right.Height()) + 1

	return y
}

func (node *Node) GetBalance() int {
	if node == nil {
		return 0
	}
	return node.left.Height() - node.right.Height()
}

func Insert(node *Node, key int) *Node {
	if node == nil {
		return NewNode(key)
	}
	if node.key == key {
		node.cnt++
		return node
	}

	if node.key > key {
		node.left = Insert(node.left, key)
	} else {
		node.right = Insert(node.right, key)
	}

	node.height = max(node.left.Height(), node.right.Height()) + 1
	balance := node.GetBalance()

	if balance > 1 && key < node.left.key {
		return rightRotate(node)
	}

	if balance < -1 && key > node.right.key {
		return leftRotate(node)
	}

	if balance > 1 && key > node.left.key {
		node.left = leftRotate(node.left)
		return rightRotate(node)
	}

	if balance < -1 && key < node.right.key {
		node.right = rightRotate(node.right)
		return leftRotate(node)
	}

	return node
}

func MinValueNode(root *Node) *Node {
	cur := root

	for cur.left != nil {
		cur = cur.left
	}

	return cur
}

func (root *Node) MinValue() int {
	if root == nil {
		return 0
	}
	node := MinValueNode(root)

	return node.key
}

func Delete(root *Node, key int) *Node {
	if root == nil {
		return nil
	}

	if key < root.key {
		root.left = Delete(root.left, key)
	} else if key > root.key {
		root.right = Delete(root.right, key)
	} else {
		root.cnt--
		if root.cnt > 0 {
			return root
		}
		if root.left == nil || root.right == nil {
			tmp := root.left
			if root.left == nil {
				tmp = root.right
			}
			root = tmp
		} else {
			tmp := MinValueNode(root.right)

			root.key = tmp.key
			root.cnt = tmp.cnt
			// make sure tmp node deleted after call delete on root.right
			tmp.cnt = 1
			root.right = Delete(root.right, tmp.key)
		}
	}

	if root == nil {
		return root
	}

	root.height = max(root.left.Height(), root.right.Height()) + 1
	balance := root.GetBalance()

	if balance > 1 && root.left.GetBalance() >= 0 {
		return rightRotate(root)
	}

	if balance > 1 && root.left.GetBalance() < 0 {
		root.left = leftRotate(root.left)
		return rightRotate(root)
	}

	if balance < -1 && root.right.GetBalance() <= 0 {
		return leftRotate(root)
	}

	if balance < -1 && root.right.GetBalance() > 0 {
		root.right = rightRotate(root.right)
		return leftRotate(root)
	}

	return root
}

func solve1(A, B, C, D []int, X, Y, Z [][]int) int {
	R := process(C, D, Z)
	R = process(B, R, Y)
	R = process(A, R, X)
	var best int = INF
	for i := 0; i < len(R); i++ {
		best = min(best, R[i])
	}
	if best >= INF {
		return -1
	}
	return best
}

func process(A, B []int, X [][]int) []int {
	n1 := len(A)
	n2 := len(B)
	cnt := make([]int, n2)
	for _, x := range X {
		cnt[x[1]-1]++
	}

	pref := make([][]int, n2)
	for i := 0; i < n2; i++ {
		pref[i] = make([]int, 0, cnt[i])
	}

	sort.Slice(X, func(i, j int) bool {
		return X[i][0] < X[j][0]
	})

	for _, x := range X {
		a, b := x[0], x[1]
		a--
		b--
		if B[b] >= INF {
			continue
		}
		pref[b] = append(pref[b], a)
	}

	tree := NewSegTree(n1)

	for i := 0; i < n2; i++ {
		if B[i] >= INF {
			continue
		}
		cur := pref[i]
		//sort.Ints(cur)
		var p int
		for j := 0; j < len(cur); j++ {
			if cur[j] > p {
				tree.Update(p, cur[j]-1, B[i])
			}
			p = cur[j] + 1
		}
		if p < n1 {
			tree.Update(p, n1-1, B[i])
		}
	}

	res := make([]int, n1)

	for i := 0; i < n1; i++ {
		tmp := tree.Query(i, i)
		if tmp < INF {
			res[i] = tmp + A[i]
		} else {
			res[i] = INF
		}
	}
	return res
}

type SegTree struct {
	arr  []int
	lazy []int
	n    int
}

func NewSegTree(n int) *SegTree {
	arr := make([]int, 4*n)
	for i := 0; i < len(arr); i++ {
		arr[i] = INF
	}
	lazy := make([]int, 4*n)
	return &SegTree{arr, lazy, n}
}

func (tree *SegTree) Update(L, R int, V int) {
	var loop func(i int, l, r, v int)
	loop = func(i int, l, r, v int) {
		if r < L || R < l {
			return
		}
		if L <= l && r <= R {
			tree.change(i, v)
			return
		}
		tree.push(i)
		mid := (l + r) / 2
		loop(2*i, l, mid, min(v, tree.arr[i]))
		loop(2*i+1, mid+1, r, min(v, tree.arr[i]))
		tree.arr[i] = min(tree.arr[2*i], tree.arr[2*i+1])
	}
	loop(1, 0, tree.n-1, V)
}

func (tree *SegTree) Query(L, R int) int {
	var loop func(i int, l, r int) int
	loop = func(i int, l, r int) int {
		if r < L || R < l {
			return INF
		}
		if L <= l && r <= R {
			return tree.arr[i]
		}

		tree.push(i)

		mid := (l + r) / 2
		a := loop(2*i, l, mid)
		b := loop(2*i+1, mid+1, r)
		return min(a, b)
	}
	return loop(1, 0, tree.n-1)
}

func (tree *SegTree) change(id int, v int) {
	if tree.arr[id] > v {
		tree.arr[id] = v
		tree.lazy[id] = v
	}
}

func (tree *SegTree) push(id int) {
	if tree.lazy[id] > 0 {
		tree.change(id*2, tree.lazy[id])
		tree.change(id*2+1, tree.lazy[id])
		tree.lazy[id] = 0
	}
}

func min(a, b int) int {
	if a <= b {
		return a
	}
	return b
}

package main

import (
	"bufio"
	"fmt"
	"os"
	"sort"
)

func main() {
	reader := bufio.NewReader(os.Stdin)

	first := readNNums(reader, 4)
	A := readNNums(reader, first[0])
	B := readNNums(reader, first[1])
	C := readNNums(reader, first[2])
	D := readNNums(reader, first[3])

	m := readNum(reader)
	X := make([][]int, m)
	for i := 0; i < m; i++ {
		X[i] = readNNums(reader, 2)
	}
	m = readNum(reader)
	Y := make([][]int, m)
	for i := 0; i < m; i++ {
		Y[i] = readNNums(reader, 2)
	}
	m = readNum(reader)
	Z := make([][]int, m)
	for i := 0; i < m; i++ {
		Z[i] = readNNums(reader, 2)
	}
	fmt.Println(solve(A, B, C, D, X, Y, Z))
}

func readInt(bytes []byte, from int, val *int) int {
	i := from
	sign := 1
	if bytes[i] == '-' {
		sign = -1
		i++
	}
	tmp := 0
	for i < len(bytes) && bytes[i] >= '0' && bytes[i] <= '9' {
		tmp = tmp*10 + int(bytes[i]-'0')
		i++
	}
	*val = tmp * sign
	return i
}

func readNum(reader *bufio.Reader) (a int) {
	bs, _ := reader.ReadBytes('\n')
	readInt(bs, 0, &a)
	return
}

func readTwoNums(reader *bufio.Reader) (a int, b int) {
	res := readNNums(reader, 2)
	a, b = res[0], res[1]
	return
}

func readThreeNums(reader *bufio.Reader) (a int, b int, c int) {
	res := readNNums(reader, 3)
	a, b, c = res[0], res[1], res[2]
	return
}

func readNNums(reader *bufio.Reader, n int) []int {
	res := make([]int, n)
	x := 0
	bs, _ := reader.ReadBytes('\n')
	for i := 0; i < n; i++ {
		for x < len(bs) && (bs[x] < '0' || bs[x] > '9') && bs[x] != '-' {
			x++
		}
		x = readInt(bs, x, &res[i])
	}
	return res
}

func readUint64(bytes []byte, from int, val *uint64) int {
	i := from

	var tmp uint64
	for i < len(bytes) && bytes[i] >= '0' && bytes[i] <= '9' {
		tmp = tmp*10 + uint64(bytes[i]-'0')
		i++
	}
	*val = tmp

	return i
}

const MAX_N = 150010
const INF = 400000010

func solve(A, B, C, D []int, X, Y, Z [][]int) int {
	R := process(C, D, Z)
	R = process(B, R, Y)
	R = process(A, R, X)
	var best int = INF
	for i := 0; i < len(R); i++ {
		best = min(best, R[i])
	}
	if best >= INF {
		return -1
	}
	return best
}

func process(A, B []int, X [][]int) []int {
	n1 := len(A)
	n2 := len(B)
	cnt := make([]int, n2)
	for _, x := range X {
		cnt[x[1]-1]++
	}

	pref := make([][]int, n2)
	for i := 0; i < n2; i++ {
		pref[i] = make([]int, 0, cnt[i])
	}

	sort.Slice(X, func(i, j int) bool {
		return X[i][0] < X[j][0]
	})

	for _, x := range X {
		a, b := x[0], x[1]
		a--
		b--
		if B[b] >= INF {
			continue
		}
		pref[b] = append(pref[b], a)
	}

	tree := NewSegTree(n1)

	for i := 0; i < n2; i++ {
		if B[i] >= INF {
			continue
		}
		cur := pref[i]
		//sort.Ints(cur)
		var p int
		for j := 0; j < len(cur); j++ {
			if cur[j] > p {
				tree.Update(p, cur[j]-1, B[i])
			}
			p = cur[j] + 1
		}
		if p < n1 {
			tree.Update(p, n1-1, B[i])
		}
	}

	res := make([]int, n1)

	for i := 0; i < n1; i++ {
		tmp := tree.Query(i, i)
		if tmp < INF {
			res[i] = tmp + A[i]
		} else {
			res[i] = INF
		}
	}
	return res
}

type SegTree struct {
	arr  []int
	lazy []int
	n    int
}

func NewSegTree(n int) *SegTree {
	arr := make([]int, 4*n)
	for i := 0; i < len(arr); i++ {
		arr[i] = INF
	}
	lazy := make([]int, 4*n)
	return &SegTree{arr, lazy, n}
}

func (tree *SegTree) Update(L, R int, V int) {
	var loop func(i int, l, r int)
	loop = func(i int, l, r int) {
		if r < L || R < l {
			return
		}
		if L <= l && r <= R {
			tree.change(i, V)
			return
		}
		tree.push(i)
		mid := (l + r) / 2
		loop(2*i, l, mid)
		loop(2*i+1, mid+1, r)
		tree.arr[i] = min(tree.arr[2*i], tree.arr[2*i+1])
	}
	loop(1, 0, tree.n-1)
}

func (tree *SegTree) Query(L, R int) int {
	var loop func(i int, l, r int) int
	loop = func(i int, l, r int) int {
		if r < L || R < l {
			return INF
		}
		if L <= l && r <= R {
			return tree.arr[i]
		}

		tree.push(i)

		mid := (l + r) / 2
		a := loop(2*i, l, mid)
		b := loop(2*i+1, mid+1, r)
		return min(a, b)
	}
	return loop(1, 0, tree.n-1)
}

func (tree *SegTree) change(id int, v int) {
	if tree.arr[id] > v {
		tree.arr[id] = v
		tree.lazy[id] = v
	}
}

func (tree *SegTree) push(id int) {
	if tree.lazy[id] > 0 {
		tree.change(id*2, tree.lazy[id])
		tree.change(id*2+1, tree.lazy[id])
		tree.lazy[id] = 0
	}
}

func min(a, b int) int {
	if a <= b {
		return a
	}
	return b
}

package main

import (
	"bufio"
	"fmt"
	"os"
	"sort"
)

func main() {
	reader := bufio.NewReader(os.Stdin)

	first := readNNums(reader, 4)
	A := readNNums(reader, first[0])
	B := readNNums(reader, first[1])
	C := readNNums(reader, first[2])
	D := readNNums(reader, first[3])

	m := readNum(reader)
	X := make([][]int, m)
	for i := 0; i < m; i++ {
		X[i] = readNNums(reader, 2)
	}
	m = readNum(reader)
	Y := make([][]int, m)
	for i := 0; i < m; i++ {
		Y[i] = readNNums(reader, 2)
	}
	m = readNum(reader)
	Z := make([][]int, m)
	for i := 0; i < m; i++ {
		Z[i] = readNNums(reader, 2)
	}
	fmt.Println(solve(A, B, C, D, X, Y, Z))
}

func readInt(bytes []byte, from int, val *int) int {
	i := from
	sign := 1
	if bytes[i] == '-' {
		sign = -1
		i++
	}
	tmp := 0
	for i < len(bytes) && bytes[i] >= '0' && bytes[i] <= '9' {
		tmp = tmp*10 + int(bytes[i]-'0')
		i++
	}
	*val = tmp * sign
	return i
}

func readNum(reader *bufio.Reader) (a int) {
	bs, _ := reader.ReadBytes('\n')
	readInt(bs, 0, &a)
	return
}

func readTwoNums(reader *bufio.Reader) (a int, b int) {
	res := readNNums(reader, 2)
	a, b = res[0], res[1]
	return
}

func readThreeNums(reader *bufio.Reader) (a int, b int, c int) {
	res := readNNums(reader, 3)
	a, b, c = res[0], res[1], res[2]
	return
}

func readNNums(reader *bufio.Reader, n int) []int {
	res := make([]int, n)
	x := 0
	bs, _ := reader.ReadBytes('\n')
	for i := 0; i < n; i++ {
		for x < len(bs) && (bs[x] < '0' || bs[x] > '9') && bs[x] != '-' {
			x++
		}
		x = readInt(bs, x, &res[i])
	}
	return res
}

func readUint64(bytes []byte, from int, val *uint64) int {
	i := from

	var tmp uint64
	for i < len(bytes) && bytes[i] >= '0' && bytes[i] <= '9' {
		tmp = tmp*10 + uint64(bytes[i]-'0')
		i++
	}
	*val = tmp

	return i
}

const MAX_N = 150010
const INF = 400000010

func solve(A, B, C, D []int, X, Y, Z [][]int) int {
	R := process(C, D, Z)
	R = process(B, R, Y)
	R = process(A, R, X)
	var best int = INF
	for i := 0; i < len(R); i++ {
		best = min(best, R[i])
	}
	if best >= INF {
		return -1
	}
	return best
}

func process(A, B []int, X [][]int) []int {
	n1 := len(A)
	n2 := len(B)
	cnt := make([]int, n2)
	for _, x := range X {
		cnt[x[1]-1]++
	}

	pref := make([][]int, n2)
	for i := 0; i < n2; i++ {
		pref[i] = make([]int, 0, cnt[i])
	}

	sort.Slice(X, func(i, j int) bool {
		return X[i][0] < X[j][0]
	})

	for _, x := range X {
		a, b := x[0], x[1]
		a--
		b--
		if B[b] >= INF {
			continue
		}
		pref[b] = append(pref[b], a)
	}

	tree := NewSegTree(n1)

	for i := 0; i < n2; i++ {
		cur := pref[i]
		//sort.Ints(cur)
		var p int
		for j := 0; j < len(cur); j++ {
			if cur[j]-1 >= p {
				tree.Update(p, cur[j]-1, B[i])
			}
			p = cur[j] + 1
		}
		if p < n1 {
			tree.Update(p, n1-1, B[i])
		}
	}

	res := make([]int, n1)

	for i := 0; i < n1; i++ {
		tmp := tree.Query(i, i)
		if tmp < INF {
			res[i] = tmp + A[i]
		} else {
			res[i] = INF
		}
	}
	return res
}

type SegTree struct {
	arr  []int
	lazy []int
	n    int
}

func NewSegTree(n int) *SegTree {
	arr := make([]int, 4*n)
	for i := 0; i < len(arr); i++ {
		arr[i] = INF
	}
	lazy := make([]int, 4*n)
	return &SegTree{arr, lazy, n}
}

func (tree *SegTree) Update(L, R int, V int) {
	var loop func(i int, l, r int)
	loop = func(i int, l, r int) {
		if r < L || R < l {
			return
		}
		if L <= l && r <= R {
			tree.change(i, V)
			return
		}
		tree.push(i)
		mid := (l + r) / 2
		loop(2*i, l, mid)
		loop(2*i+1, mid+1, r)
		tree.arr[i] = min(tree.arr[2*i], tree.arr[2*i+1])
	}
	loop(1, 0, tree.n-1)
}

func (tree *SegTree) Query(L, R int) int {
	var loop func(i int, l, r int) int
	loop = func(i int, l, r int) int {
		if r < L || R < l {
			return INF
		}
		if L <= l && r <= R {
			return tree.arr[i]
		}

		tree.push(i)

		mid := (l + r) / 2
		a := loop(2*i, l, mid)
		b := loop(2*i+1, mid+1, r)
		return min(a, b)
	}
	return loop(1, 0, tree.n-1)
}

func (tree *SegTree) change(id int, v int) {
	if id < len(tree.arr) && tree.arr[id] > v {
		tree.arr[id] = v
		tree.lazy[id] = v
	}
}

func (tree *SegTree) push(id int) {
	if tree.lazy[id] > 0 {
		tree.change(id*2, tree.lazy[id])
		tree.change(id*2+1, tree.lazy[id])
	}
	tree.lazy[id] = 0
}

func min(a, b int) int {
	if a <= b {
		return a
	}
	return b
}

package main

import (
	"bufio"
	"fmt"
	"os"
	"sort"
)

func main() {
	reader := bufio.NewReader(os.Stdin)

	first := readNNums(reader, 4)
	A := readNNums(reader, first[0])
	B := readNNums(reader, first[1])
	C := readNNums(reader, first[2])
	D := readNNums(reader, first[3])

	m := readNum(reader)
	X := make([][]int, m)
	for i := 0; i < m; i++ {
		X[i] = readNNums(reader, 2)
	}
	m = readNum(reader)
	Y := make([][]int, m)
	for i := 0; i < m; i++ {
		Y[i] = readNNums(reader, 2)
	}
	m = readNum(reader)
	Z := make([][]int, m)
	for i := 0; i < m; i++ {
		Z[i] = readNNums(reader, 2)
	}
	fmt.Println(solve(A, B, C, D, X, Y, Z))
}

func readInt(bytes []byte, from int, val *int) int {
	i := from
	sign := 1
	if bytes[i] == '-' {
		sign = -1
		i++
	}
	tmp := 0
	for i < len(bytes) && bytes[i] >= '0' && bytes[i] <= '9' {
		tmp = tmp*10 + int(bytes[i]-'0')
		i++
	}
	*val = tmp * sign
	return i
}

func readNum(reader *bufio.Reader) (a int) {
	bs, _ := reader.ReadBytes('\n')
	readInt(bs, 0, &a)
	return
}

func readTwoNums(reader *bufio.Reader) (a int, b int) {
	res := readNNums(reader, 2)
	a, b = res[0], res[1]
	return
}

func readThreeNums(reader *bufio.Reader) (a int, b int, c int) {
	res := readNNums(reader, 3)
	a, b, c = res[0], res[1], res[2]
	return
}

func readNNums(reader *bufio.Reader, n int) []int {
	res := make([]int, n)
	x := 0
	bs, _ := reader.ReadBytes('\n')
	for i := 0; i < n; i++ {
		for x < len(bs) && (bs[x] < '0' || bs[x] > '9') && bs[x] != '-' {
			x++
		}
		x = readInt(bs, x, &res[i])
	}
	return res
}

func readUint64(bytes []byte, from int, val *uint64) int {
	i := from

	var tmp uint64
	for i < len(bytes) && bytes[i] >= '0' && bytes[i] <= '9' {
		tmp = tmp*10 + uint64(bytes[i]-'0')
		i++
	}
	*val = tmp

	return i
}

const MAX_N = 150010
const INF = 400000010

func solve(A, B, C, D []int, X, Y, Z [][]int) int {
	tree := NewSegTree(MAX_N)
	R := process(tree, C, D, Z)
	R = process(tree, B, R, Y)
	R = process(tree, A, R, X)
	var best int = INF
	for i := 0; i < len(R); i++ {
		best = min(best, R[i])
	}
	if best >= INF {
		return -1
	}
	return best
}

func process(tree *SegTree, A, B []int, X [][]int) []int {
	n1 := len(A)
	n2 := len(B)
	cnt := make([]int, n2)
	for _, x := range X {
		cnt[x[1]-1]++
	}

	pref := make([][]int, n2)
	for i := 0; i < n2; i++ {
		pref[i] = make([]int, 0, cnt[i])
	}

	sort.Slice(X, func(i, j int) bool {
		return X[i][0] < X[j][0]
	})

	for _, x := range X {
		a, b := x[0], x[1]
		a--
		b--
		if B[b] >= INF {
			continue
		}
		pref[b] = append(pref[b], a)
	}

	tree.Reset()
	for i := 0; i < n2; i++ {
		cur := pref[i]
		//sort.Ints(cur)
		var p int
		for j := 0; j < len(cur); j++ {
			if cur[j]-1 >= p {
				tree.Update(p, cur[j]-1, B[i])
			}
			p = cur[j] + 1
		}
		if p < n1 {
			tree.Update(p, n1-1, B[i])
		}
	}

	res := make([]int, n1)

	for i := 0; i < n1; i++ {
		tmp := tree.Query(i, i)
		if tmp < INF {
			res[i] = tmp + A[i]
		} else {
			res[i] = INF
		}
	}
	return res
}

type SegTree struct {
	arr  []int
	lazy []int
	n    int
}

func NewSegTree(n int) *SegTree {
	arr := make([]int, 4*n)
	for i := 0; i < len(arr); i++ {
		arr[i] = INF
	}
	lazy := make([]int, 4*n)
	return &SegTree{arr, lazy, n}
}

func (tree *SegTree) Reset() {
	for i := 0; i < len(tree.arr); i++ {
		tree.arr[i] = INF
		tree.lazy[i] = 0
	}
}

func (tree *SegTree) Update(L, R int, V int) {
	var loop func(i int, l, r int)
	loop = func(i int, l, r int) {
		if r < L || R < l {
			return
		}
		if L <= l && r <= R {
			tree.change(i, V)
			return
		}
		tree.push(i)
		mid := (l + r) / 2
		loop(2*i, l, mid)
		loop(2*i+1, mid+1, r)
		tree.arr[i] = min(tree.arr[2*i], tree.arr[2*i+1])
	}
	loop(1, 0, tree.n-1)
}

func (tree *SegTree) Query(L, R int) int {
	var loop func(i int, l, r int) int
	loop = func(i int, l, r int) int {
		tree.push(i)

		if r < L || R < l {
			return INF
		}
		if L <= l && r <= R {
			return tree.arr[i]
		}
		mid := (l + r) / 2
		a := loop(2*i, l, mid)
		b := loop(2*i+1, mid+1, r)
		tree.arr[i] = min(tree.arr[i*2], tree.arr[i*2+1])
		return min(a, b)
	}
	return loop(1, 0, tree.n-1)
}

func (tree *SegTree) change(id int, v int) {
	if id < len(tree.arr) && tree.arr[id] > v {
		tree.arr[id] = v
		tree.lazy[id] = v
	}
}

func (tree *SegTree) push(id int) {
	if tree.lazy[id] > 0 {
		tree.change(id*2, tree.lazy[id])
		tree.change(id*2+1, tree.lazy[id])
	}
	tree.lazy[id] = 0
}

func min(a, b int) int {
	if a <= b {
		return a
	}
	return b
}

package main

import (
	"bufio"
	"fmt"
	"os"
	"sort"
)

func main() {
	reader := bufio.NewReader(os.Stdin)

	first := readNNums(reader, 4)
	A := readNNums(reader, first[0])
	B := readNNums(reader, first[1])
	C := readNNums(reader, first[2])
	D := readNNums(reader, first[3])

	m := readNum(reader)
	X := make([][]int, m)
	for i := 0; i < m; i++ {
		X[i] = readNNums(reader, 2)
	}
	m = readNum(reader)
	Y := make([][]int, m)
	for i := 0; i < m; i++ {
		Y[i] = readNNums(reader, 2)
	}
	m = readNum(reader)
	Z := make([][]int, m)
	for i := 0; i < m; i++ {
		Z[i] = readNNums(reader, 2)
	}
	fmt.Println(solve(A, B, C, D, X, Y, Z))
}

func readInt(bytes []byte, from int, val *int) int {
	i := from
	sign := 1
	if bytes[i] == '-' {
		sign = -1
		i++
	}
	tmp := 0
	for i < len(bytes) && bytes[i] >= '0' && bytes[i] <= '9' {
		tmp = tmp*10 + int(bytes[i]-'0')
		i++
	}
	*val = tmp * sign
	return i
}

func readNum(reader *bufio.Reader) (a int) {
	bs, _ := reader.ReadBytes('\n')
	readInt(bs, 0, &a)
	return
}

func readTwoNums(reader *bufio.Reader) (a int, b int) {
	res := readNNums(reader, 2)
	a, b = res[0], res[1]
	return
}

func readThreeNums(reader *bufio.Reader) (a int, b int, c int) {
	res := readNNums(reader, 3)
	a, b, c = res[0], res[1], res[2]
	return
}

func readNNums(reader *bufio.Reader, n int) []int {
	res := make([]int, n)
	x := 0
	bs, _ := reader.ReadBytes('\n')
	for i := 0; i < n; i++ {
		for x < len(bs) && (bs[x] < '0' || bs[x] > '9') && bs[x] != '-' {
			x++
		}
		x = readInt(bs, x, &res[i])
	}
	return res
}

func readUint64(bytes []byte, from int, val *uint64) int {
	i := from

	var tmp uint64
	for i < len(bytes) && bytes[i] >= '0' && bytes[i] <= '9' {
		tmp = tmp*10 + uint64(bytes[i]-'0')
		i++
	}
	*val = tmp

	return i
}

const MAX_N = 150010
const INF = 400000010

func solve(A, B, C, D []int, X, Y, Z [][]int) int {
	tree := NewSegTree(MAX_N)
	R := process(tree, C, D, Z)
	R = process(tree, B, R, Y)
	R = process(tree, A, R, X)
	var best int = INF
	for i := 0; i < len(R); i++ {
		best = min(best, R[i])
	}
	if best >= INF {
		return -1
	}
	return best
}

func process(tree *SegTree, A, B []int, X [][]int) []int {
	n1 := len(A)
	n2 := len(B)
	cnt := make([]int, n2)
	for _, x := range X {
		cnt[x[1]-1]++
	}

	pref := make([][]int, n2)
	for i := 0; i < n2; i++ {
		pref[i] = make([]int, 0, cnt[i])
	}

	sort.Slice(X, func(i, j int) bool {
		return X[i][0] < X[j][0]
	})

	for _, x := range X {
		a, b := x[0], x[1]
		a--
		b--
		if B[b] >= INF {
			continue
		}
		pref[b] = append(pref[b], a)
	}

	tree.Reset()
	for i := 0; i < n2; i++ {
		cur := pref[i]
		//sort.Ints(cur)
		var p int
		for j := 0; j < len(cur); j++ {
			if cur[j]-1 >= p {
				tree.Update(p, cur[j]-1, B[i])
			}
			p = cur[j] + 1
		}
		if p < n1 {
			tree.Update(p, n1-1, B[i])
		}
	}

	res := make([]int, n1)

	for i := 0; i < n1; i++ {
		tmp := tree.Query(i, i)
		if tmp < INF {
			res[i] = tmp + A[i]
		} else {
			res[i] = INF
		}
	}
	return res
}

type SegTree struct {
	arr  []int
	lazy []int
	n    int
}

func NewSegTree(n int) *SegTree {
	arr := make([]int, 4*n)
	for i := 0; i < len(arr); i++ {
		arr[i] = INF
	}
	lazy := make([]int, 4*n)
	return &SegTree{arr, lazy, n}
}

func (tree *SegTree) Reset() {
	for i := 0; i < len(tree.arr); i++ {
		tree.arr[i] = INF
		tree.lazy[i] = 0
	}
}

func (tree *SegTree) Update(L, R int, V int) {
	var loop func(i int, l, r int)
	loop = func(i int, l, r int) {
		if r < L || R < l {
			return
		}
		if L <= l && r <= R {
			tree.change(i, V)
			return
		}
		tree.push(i)
		mid := (l + r) / 2
		loop(2*i, l, mid)
		loop(2*i+1, mid+1, r)
		tree.arr[i] = min(tree.arr[2*i], tree.arr[2*i+1])
	}
	loop(1, 0, tree.n-1)
}

func (tree *SegTree) Query(L, R int) int {
	var loop func(i int, l, r int) int
	loop = func(i int, l, r int) int {
		if r < L || R < l {
			return INF
		}
		if L <= l && r <= R {
			return tree.arr[i]
		}
		tree.push(i)
		mid := (l + r) / 2
		a := loop(2*i, l, mid)
		b := loop(2*i+1, mid+1, r)
		tree.arr[i] = min(tree.arr[i*2], tree.arr[i*2+1])
		return min(a, b)
	}
	return loop(1, 0, tree.n-1)
}

func (tree *SegTree) change(id int, v int) {
	if tree.arr[id] > v {
		tree.arr[id] = v
		tree.lazy[id] = v
	}
}

func (tree *SegTree) push(id int) {
	if tree.lazy[id] > 0 {
		tree.change(id*2, tree.lazy[id])
		tree.change(id*2+1, tree.lazy[id])
	}
	tree.lazy[id] = 0
}

func min(a, b int) int {
	if a <= b {
		return a
	}
	return b
}

package main

import (
	"bufio"
	"fmt"
	"os"
	"sort"
)

func main() {
	reader := bufio.NewReader(os.Stdin)

	first := readNNums(reader, 4)
	A := readNNums(reader, first[0])
	B := readNNums(reader, first[1])
	C := readNNums(reader, first[2])
	D := readNNums(reader, first[3])

	m := readNum(reader)
	X := make([][]int, m)
	for i := 0; i < m; i++ {
		X[i] = readNNums(reader, 2)
	}
	m = readNum(reader)
	Y := make([][]int, m)
	for i := 0; i < m; i++ {
		Y[i] = readNNums(reader, 2)
	}
	m = readNum(reader)
	Z := make([][]int, m)
	for i := 0; i < m; i++ {
		Z[i] = readNNums(reader, 2)
	}
	fmt.Println(solve(A, B, C, D, X, Y, Z))
}

func readInt(bytes []byte, from int, val *int) int {
	i := from
	sign := 1
	if bytes[i] == '-' {
		sign = -1
		i++
	}
	tmp := 0
	for i < len(bytes) && bytes[i] >= '0' && bytes[i] <= '9' {
		tmp = tmp*10 + int(bytes[i]-'0')
		i++
	}
	*val = tmp * sign
	return i
}

func readNum(reader *bufio.Reader) (a int) {
	bs, _ := reader.ReadBytes('\n')
	readInt(bs, 0, &a)
	return
}

func readTwoNums(reader *bufio.Reader) (a int, b int) {
	res := readNNums(reader, 2)
	a, b = res[0], res[1]
	return
}

func readThreeNums(reader *bufio.Reader) (a int, b int, c int) {
	res := readNNums(reader, 3)
	a, b, c = res[0], res[1], res[2]
	return
}

func readNNums(reader *bufio.Reader, n int) []int {
	res := make([]int, n)
	x := 0
	bs, _ := reader.ReadBytes('\n')
	for i := 0; i < n; i++ {
		for x < len(bs) && (bs[x] < '0' || bs[x] > '9') && bs[x] != '-' {
			x++
		}
		x = readInt(bs, x, &res[i])
	}
	return res
}

func readUint64(bytes []byte, from int, val *uint64) int {
	i := from

	var tmp uint64
	for i < len(bytes) && bytes[i] >= '0' && bytes[i] <= '9' {
		tmp = tmp*10 + uint64(bytes[i]-'0')
		i++
	}
	*val = tmp

	return i
}

const MAX_N = 150010
const INF = 400000010

func solve(A, B, C, D []int, X, Y, Z [][]int) int {
	tree := NewSegTree(MAX_N)
	R := process(tree, C, D, Z)
	R = process(tree, B, R, Y)
	R = process(tree, A, R, X)
	var best int = INF
	for i := 0; i < len(R); i++ {
		best = min(best, R[i])
	}
	if best >= INF {
		return -1
	}
	return best
}

func process(tree *SegTree, A, B []int, X [][]int) []int {
	n1 := len(A)
	n2 := len(B)
	cnt := make([]int, n2)
	for _, x := range X {
		cnt[x[1]-1]++
	}

	pref := make([][]int, n2)
	for i := 0; i < n2; i++ {
		pref[i] = make([]int, 0, cnt[i])
	}

	sort.Slice(X, func(i, j int) bool {
		return X[i][0] < X[j][0]
	})

	for _, x := range X {
		a, b := x[0], x[1]
		a--
		b--
		if B[b] >= INF {
			continue
		}
		pref[b] = append(pref[b], a)
	}

	tree.Reset()
	for i := 0; i < n2; i++ {
		cur := pref[i]
		//sort.Ints(cur)
		var p int
		for j := 0; j < len(cur); j++ {
			if cur[j]-1 >= p {
				tree.Update(p, cur[j]-1, B[i])
			}
			p = cur[j] + 1
		}
		if p < n1 {
			tree.Update(p, n1-1, B[i])
		}
	}

	res := make([]int, n1)

	for i := 0; i < n1; i++ {
		tmp := tree.Query(i, i)
		if tmp < INF {
			res[i] = tmp + A[i]
		} else {
			res[i] = INF
		}
	}
	return res
}

type SegTree struct {
	arr  []int
	lazy []int
	n    int
}

func NewSegTree(n int) *SegTree {
	arr := make([]int, 4*n)
	for i := 0; i < len(arr); i++ {
		arr[i] = INF
	}
	lazy := make([]int, 4*n)
	return &SegTree{arr, lazy, n}
}

func (tree *SegTree) Reset() {
	for i := 0; i < len(tree.arr); i++ {
		tree.arr[i] = INF
		tree.lazy[i] = 0
	}
}

func (tree *SegTree) Update(L, R int, V int) {
	var loop func(i int, l, r int)
	loop = func(i int, l, r int) {
		if r < L || R < l {
			return
		}
		if L <= l && r <= R {
			tree.change(i, V)
			return
		}
		tree.push(i)
		mid := (l + r) / 2
		loop(2*i, l, mid)
		loop(2*i+1, mid+1, r)
		tree.arr[i] = min(tree.arr[2*i], tree.arr[2*i+1])
	}
	loop(1, 0, tree.n-1)
}

func (tree *SegTree) Query(L, R int) int {
	var loop func(i int, l, r int) int
	loop = func(i int, l, r int) int {
		if r < L || R < l {
			return INF
		}
		if L <= l && r <= R {
			return tree.arr[i]
		}
		tree.push(i)
		mid := (l + r) / 2
		a := loop(2*i, l, mid)
		b := loop(2*i+1, mid+1, r)
		return min(a, b)
	}
	return loop(1, 0, tree.n-1)
}

func (tree *SegTree) change(id int, v int) {
	if tree.arr[id] > v {
		tree.arr[id] = v
		tree.lazy[id] = v
	}
}

func (tree *SegTree) push(id int) {
	if tree.lazy[id] > 0 {
		tree.change(id*2, tree.lazy[id])
		tree.change(id*2+1, tree.lazy[id])
	}
	tree.lazy[id] = 0
}

func min(a, b int) int {
	if a <= b {
		return a
	}
	return b
}

package main

import (
	"bufio"
	"fmt"
	"os"
	"sort"
)

func main() {
	reader := bufio.NewReader(os.Stdin)

	first := readNNums(reader, 4)
	A := readNNums(reader, first[0])
	B := readNNums(reader, first[1])
	C := readNNums(reader, first[2])
	D := readNNums(reader, first[3])

	m := readNum(reader)
	X := make([][]int, m)
	for i := 0; i < m; i++ {
		X[i] = readNNums(reader, 2)
	}
	m = readNum(reader)
	Y := make([][]int, m)
	for i := 0; i < m; i++ {
		Y[i] = readNNums(reader, 2)
	}
	m = readNum(reader)
	Z := make([][]int, m)
	for i := 0; i < m; i++ {
		Z[i] = readNNums(reader, 2)
	}
	fmt.Println(solve(A, B, C, D, X, Y, Z))
}

func readInt(bytes []byte, from int, val *int) int {
	i := from
	sign := 1
	if bytes[i] == '-' {
		sign = -1
		i++
	}
	tmp := 0
	for i < len(bytes) && bytes[i] >= '0' && bytes[i] <= '9' {
		tmp = tmp*10 + int(bytes[i]-'0')
		i++
	}
	*val = tmp * sign
	return i
}

func readNum(reader *bufio.Reader) (a int) {
	bs, _ := reader.ReadBytes('\n')
	readInt(bs, 0, &a)
	return
}

func readTwoNums(reader *bufio.Reader) (a int, b int) {
	res := readNNums(reader, 2)
	a, b = res[0], res[1]
	return
}

func readThreeNums(reader *bufio.Reader) (a int, b int, c int) {
	res := readNNums(reader, 3)
	a, b, c = res[0], res[1], res[2]
	return
}

func readNNums(reader *bufio.Reader, n int) []int {
	res := make([]int, n)
	x := 0
	bs, _ := reader.ReadBytes('\n')
	for i := 0; i < n; i++ {
		for x < len(bs) && (bs[x] < '0' || bs[x] > '9') && bs[x] != '-' {
			x++
		}
		x = readInt(bs, x, &res[i])
	}
	return res
}

func readUint64(bytes []byte, from int, val *uint64) int {
	i := from

	var tmp uint64
	for i < len(bytes) && bytes[i] >= '0' && bytes[i] <= '9' {
		tmp = tmp*10 + uint64(bytes[i]-'0')
		i++
	}
	*val = tmp

	return i
}

const MAX_N = 150010
const INF = 1e9 + 1000

func solve(A, B, C, D []int, X, Y, Z [][]int) int {
	tree := NewSegTree(MAX_N)
	R := process(tree, C, D, Z)
	R = process(tree, B, R, Y)
	R = process(tree, A, R, X)
	var best int = INF
	for i := 0; i < len(R); i++ {
		best = min(best, R[i])
	}
	if best >= INF {
		return -1
	}
	return best
}

func process(tree *SegTree, A, B []int, X [][]int) []int {
	n1 := len(A)
	n2 := len(B)
	cnt := make([]int, n2)
	for _, x := range X {
		cnt[x[1]-1]++
	}

	pref := make([][]int, n2)
	for i := 0; i < n2; i++ {
		pref[i] = make([]int, 0, cnt[i])
	}

	sort.Slice(X, func(i, j int) bool {
		return X[i][0] < X[j][0]
	})

	for _, x := range X {
		a, b := x[0], x[1]
		a--
		b--
		if B[b] >= INF {
			continue
		}
		pref[b] = append(pref[b], a)
	}

	tree.Reset()
	for i := 0; i < n2; i++ {
		cur := pref[i]
		//sort.Ints(cur)
		var p int
		for j := 0; j < len(cur); j++ {
			if cur[j]-1 >= p {
				tree.Update(p, cur[j]-1, B[i])
			}
			p = cur[j] + 1
		}
		if p < n1 {
			tree.Update(p, n1-1, B[i])
		}
	}

	res := make([]int, n1)

	for i := 0; i < n1; i++ {
		tmp := tree.Query(i, i)
		if tmp < INF {
			res[i] = tmp + A[i]
		} else {
			res[i] = INF
		}
	}
	return res
}

type SegTree struct {
	arr  []int
	lazy []int
	n    int
}

func NewSegTree(n int) *SegTree {
	arr := make([]int, 4*n)
	for i := 0; i < len(arr); i++ {
		arr[i] = INF
	}
	lazy := make([]int, 4*n)
	return &SegTree{arr, lazy, n}
}

func (tree *SegTree) Reset() {
	for i := 0; i < len(tree.arr); i++ {
		tree.arr[i] = INF
		tree.lazy[i] = 0
	}
}

func (tree *SegTree) Update(L, R int, V int) {
	var loop func(i int, l, r int)
	loop = func(i int, l, r int) {
		if r < L || R < l {
			return
		}
		if L <= l && r <= R {
			tree.change(i, V)
			return
		}
		tree.push(i)
		mid := (l + r) / 2
		loop(2*i, l, mid)
		loop(2*i+1, mid+1, r)
		tree.arr[i] = min(tree.arr[2*i], tree.arr[2*i+1])
	}
	loop(1, 0, tree.n-1)
}

func (tree *SegTree) Query(L, R int) int {
	var loop func(i int, l, r int) int
	loop = func(i int, l, r int) int {
		if r < L || R < l {
			return INF
		}
		if L <= l && r <= R {
			return tree.arr[i]
		}
		tree.push(i)
		mid := (l + r) / 2
		a := loop(2*i, l, mid)
		b := loop(2*i+1, mid+1, r)
		return min(a, b)
	}
	return loop(1, 0, tree.n-1)
}

func (tree *SegTree) change(id int, v int) {
	if tree.arr[id] > v {
		tree.arr[id] = v
		tree.lazy[id] = v
	}
}

func (tree *SegTree) push(id int) {
	if tree.lazy[id] > 0 {
		tree.change(id*2, tree.lazy[id])
		tree.change(id*2+1, tree.lazy[id])
	}
	tree.lazy[id] = 0
}

func min(a, b int) int {
	if a <= b {
		return a
	}
	return b
}

package main

import (
	"bufio"
	"fmt"
	"os"
	"sort"
)

func main() {
	reader := bufio.NewReader(os.Stdin)

	first := readNNums(reader, 4)
	A := readNNums(reader, first[0])
	B := readNNums(reader, first[1])
	C := readNNums(reader, first[2])
	D := readNNums(reader, first[3])

	m := readNum(reader)
	X := make([][]int, m)
	for i := 0; i < m; i++ {
		X[i] = readNNums(reader, 2)
	}
	m = readNum(reader)
	Y := make([][]int, m)
	for i := 0; i < m; i++ {
		Y[i] = readNNums(reader, 2)
	}
	m = readNum(reader)
	Z := make([][]int, m)
	for i := 0; i < m; i++ {
		Z[i] = readNNums(reader, 2)
	}
	fmt.Println(solve(A, B, C, D, X, Y, Z))
}

func readInt(bytes []byte, from int, val *int) int {
	i := from
	sign := 1
	if bytes[i] == '-' {
		sign = -1
		i++
	}
	tmp := 0
	for i < len(bytes) && bytes[i] >= '0' && bytes[i] <= '9' {
		tmp = tmp*10 + int(bytes[i]-'0')
		i++
	}
	*val = tmp * sign
	return i
}

func readNum(reader *bufio.Reader) (a int) {
	bs, _ := reader.ReadBytes('\n')
	readInt(bs, 0, &a)
	return
}

func readTwoNums(reader *bufio.Reader) (a int, b int) {
	res := readNNums(reader, 2)
	a, b = res[0], res[1]
	return
}

func readThreeNums(reader *bufio.Reader) (a int, b int, c int) {
	res := readNNums(reader, 3)
	a, b, c = res[0], res[1], res[2]
	return
}

func readNNums(reader *bufio.Reader, n int) []int {
	res := make([]int, n)
	x := 0
	bs, _ := reader.ReadBytes('\n')
	for i := 0; i < n; i++ {
		for x < len(bs) && (bs[x] < '0' || bs[x] > '9') && bs[x] != '-' {
			x++
		}
		x = readInt(bs, x, &res[i])
	}
	return res
}

func readUint64(bytes []byte, from int, val *uint64) int {
	i := from

	var tmp uint64
	for i < len(bytes) && bytes[i] >= '0' && bytes[i] <= '9' {
		tmp = tmp*10 + uint64(bytes[i]-'0')
		i++
	}
	*val = tmp

	return i
}

const MAX_N = 150010
const INF = 1e9

func solve(A, B, C, D []int, X, Y, Z [][]int) int {
	tree := NewSegTree(MAX_N)
	R := process(tree, C, D, Z)
	R = process(tree, B, R, Y)
	R = process(tree, A, R, X)
	var best int = INF
	for i := 0; i < len(R); i++ {
		best = min(best, R[i])
	}
	if best == INF {
		return -1
	}
	return best
}

func process(tree *SegTree, A, B []int, X [][]int) []int {
	n1 := len(A)
	n2 := len(B)
	cnt := make([]int, n2)
	for _, x := range X {
		cnt[x[1]-1]++
	}

	pref := make([][]int, n2)
	for i := 0; i < n2; i++ {
		pref[i] = make([]int, 0, cnt[i])
	}

	sort.Slice(X, func(i, j int) bool {
		return X[i][0] < X[j][0]
	})

	for _, x := range X {
		a, b := x[0], x[1]
		a--
		b--
		pref[b] = append(pref[b], a)
	}

	tree.Reset()
	for i := 0; i < n2; i++ {
		cur := pref[i]
		//sort.Ints(cur)
		var p int
		for j := 0; j < len(cur); j++ {
			if cur[j]-1 >= p {
				tree.Update(p, cur[j]-1, B[i])
			}
			p = cur[j] + 1
		}
		if p < n1 {
			tree.Update(p, n1-1, B[i])
		}
	}

	res := make([]int, n1)

	for i := 0; i < n1; i++ {
		res[i] = min(INF, tree.Query(i, i)+A[i])
	}
	return res
}

type SegTree struct {
	arr  []int
	lazy []int
	n    int
}

func NewSegTree(n int) *SegTree {
	arr := make([]int, 4*n)
	for i := 0; i < len(arr); i++ {
		arr[i] = INF
	}
	lazy := make([]int, 4*n)
	return &SegTree{arr, lazy, n}
}

func (tree *SegTree) Reset() {
	for i := 0; i < len(tree.arr); i++ {
		tree.arr[i] = INF
		tree.lazy[i] = 0
	}
}

func (tree *SegTree) Update(L, R int, V int) {
	var loop func(i int, l, r int)
	loop = func(i int, l, r int) {
		if r < L || R < l {
			return
		}
		if L <= l && r <= R {
			tree.change(i, V)
			return
		}
		tree.push(i)
		mid := (l + r) / 2
		loop(2*i, l, mid)
		loop(2*i+1, mid+1, r)
		tree.arr[i] = min(tree.arr[2*i], tree.arr[2*i+1])
	}
	loop(1, 0, tree.n-1)
}

func (tree *SegTree) Query(L, R int) int {
	var loop func(i int, l, r int) int
	loop = func(i int, l, r int) int {
		if r < L || R < l {
			return INF
		}
		if L <= l && r <= R {
			return tree.arr[i]
		}
		tree.push(i)
		mid := (l + r) / 2
		a := loop(2*i, l, mid)
		b := loop(2*i+1, mid+1, r)
		return min(a, b)
	}
	return loop(1, 0, tree.n-1)
}

func (tree *SegTree) change(id int, v int) {
	if tree.arr[id] > v {
		tree.arr[id] = v
		tree.lazy[id] = v
	}
}

func (tree *SegTree) push(id int) {
	if tree.lazy[id] > 0 {
		tree.change(id*2, tree.lazy[id])
		tree.change(id*2+1, tree.lazy[id])
	}
	tree.lazy[id] = 0
}

func min(a, b int) int {
	if a <= b {
		return a
	}
	return b
}

package main

import (
	"bufio"
	"fmt"
	"os"
	"sort"
)

const inf int64 = 1 << 60

func solveForCurrentAndPrevious(curr, prev []int64, notok [][]int) {
	seg := newSegtree(prev)

	for i := range curr {
		ans := inf

		for j := 1; j < len(notok[i]); j++ {
			prevIdx, currIdx := notok[i][j-1], notok[i][j]
			if prevIdx+1 > currIdx-1 {
				continue
			}
			ans = min(ans, seg.getMin(0, prevIdx+1, currIdx-1))
		}

		if ans != inf {
			curr[i] += ans
		} else {
			curr[i] = inf
		}
	}
}

func solveE(a [4][]int64, notok [3][][]int) {
	for i := 0; i < 3; i++ {
		prev, curr, notok := a[i], a[i+1], notok[i]
		solveForCurrentAndPrevious(curr, prev, notok)
	}

	ans := min(a[3]...)

	st := newSegtree(a[3])
	tmp := st.getMin(0, 0, len(a[3])-1)
	if tmp != ans {
		panic(fmt.Sprintf("%d\n%d", ans, tmp))
	}

	if ans == inf {
		ans = -1
	}
	printf("%d", ans)
}

func main() {
	defer writer.Flush()
	// redirectInputToFile(reader, "input.txt")

	T := 1
	// scan(&T)

	for t := 0; t < T; t++ {
		var n [4]int
		for i := range n {
			scan(&n[i])
		}

		var a [4][]int64
		for i := range n {
			a[i] = make([]int64, n[i])
			for j := range a[i] {
				scan(&a[i][j])
			}
		}

		var m [3]int
		var notok [3][][]int
		for i := range m {
			notok[i] = make([][]int, n[i+1])

			scan(&m[i])
			for j := 0; j < m[i]; j++ {
				u, v := 0, 0
				scan(&u, &v)
				notok[i][v-1] = append(notok[i][v-1], u-1)
			}

			for j := range notok[i] {
				notok[i][j] = append(notok[i][j], -1, n[i])
				arr := notok[i][j]
				sort.Slice(arr, func(i, j int) bool { return arr[i] < arr[j] })
			}
		}

		solveE(a, notok)
	}
}

var reader *bufio.Reader = bufio.NewReader(os.Stdin)
var writer *bufio.Writer = bufio.NewWriter(os.Stdout)

func scan(a ...interface{})             { fmt.Fscan(reader, a...) }
func printf(f string, a ...interface{}) { fmt.Fprintf(writer, f, a...) }

func redirectInputToFile(r *bufio.Reader, fp string) {
	f, err := os.Open(fp)
	if err != nil {
		panic(err)
	}
	r.Reset(f)
}

// ------------------

type segtree []*segtreenode

type segtreenode struct {
	node, l, r int
	segtreedata
}

type segtreedata struct {
	min int64
}

func newSegtree(v []int64) *segtree {
	tr := make(segtree, 4*len(v))
	tr.build(0, v, 0, len(v)-1)
	return &tr
}

func (tree segtree) build(node int, v []int64, l, r int) {
	tree[node] = &segtreenode{
		node: node, l: l, r: r,
	}

	if l == r {
		tree[node].min = v[l]
		return
	}

	m := l + (r-l)/2
	tree.build(2*node+1, v, l, m)
	tree.build(2*node+2, v, m+1, r)

	tree[node].min = min(tree[2*node+1].min, tree[2*node+2].min)
}

func (tree segtree) getMin(node, l, r int) int64 {
	if l <= tree[node].l && tree[node].r <= r {
		return tree[node].min
	}

	nextNode := 2*node + 1
	if l > tree[node].l+(tree[node].r-tree[node].l)/2 {
		nextNode++
	}

	return tree.getMin(nextNode, l, r)
}

func min(nums ...int64) int64 {
	mn := nums[0]
	for _, x := range nums {
		if mn > x {
			mn = x
		}
	}
	return mn
}

package main

import (
	"bufio"
	"fmt"
	"os"
	"sort"
)

const inf int64 = 1 << 60

func solveForCurrentAndPrevious(curr, prev []int64, notok [][]int) {
	seg := newSegtree(prev)

	for i := range curr {
		ans := inf
		edges := notok[i]

		for j := 1; j < len(edges); j++ {
			prevIdx, currIdx := edges[j-1], edges[j]
			if prevIdx+1 <= currIdx-1 {
				ans = min(ans, seg.getMin(0, prevIdx+1, currIdx-1))
			}
		}

		if ans != inf {
			curr[i] += ans
		} else {
			curr[i] = inf
		}
	}
}

func solveE(a [4][]int64, notok [3][][]int) {
	for i := 0; i < 3; i++ {
		prev, curr, notok := a[i], a[i+1], notok[i]
		solveForCurrentAndPrevious(curr, prev, notok)
	}

	ans := inf
	for i := range a[3] {
		ans = min(ans, a[3][i])
	}

	if ans == inf {
		ans = -1
	}

	printf("%d", ans)
}

func main() {
	defer writer.Flush()
	// redirectInputToFile(reader, "input.txt")

	T := 1
	// scan(&T)

	for t := 0; t < T; t++ {
		var n [4]int
		for i := range n {
			scan(&n[i])
		}

		var a [4][]int64
		for i := range n {
			a[i] = make([]int64, n[i])
			for j := range a[i] {
				scan(&a[i][j])
			}
		}

		var m [3]int
		var notok [3][][]int
		for i := range m {
			notok[i] = make([][]int, n[i+1])

			scan(&m[i])
			for j := 0; j < m[i]; j++ {
				u, v := 0, 0
				scan(&u, &v)
				notok[i][v-1] = append(notok[i][v-1], u-1)
			}

			for j := range notok[i] {
				notok[i][j] = append(notok[i][j], -1, n[i])
				arr := notok[i][j]
				sort.Slice(arr, func(i, j int) bool { return arr[i] < arr[j] })
			}
		}

		solveE(a, notok)
	}
}

var reader *bufio.Reader = bufio.NewReader(os.Stdin)
var writer *bufio.Writer = bufio.NewWriter(os.Stdout)

func scan(a ...interface{})             { fmt.Fscan(reader, a...) }
func printf(f string, a ...interface{}) { fmt.Fprintf(writer, f, a...) }

func redirectInputToFile(r *bufio.Reader, fp string) {
	f, err := os.Open(fp)
	if err != nil {
		panic(err)
	}
	r.Reset(f)
}

// ------------------

type segtree []*segtreenode

type segtreenode struct {
	node, l, r int
	segtreedata
}

type segtreedata struct {
	min int64
}

func newSegtree(v []int64) *segtree {
	tr := make(segtree, 4*len(v))
	tr.build(0, v, 0, len(v)-1)
	return &tr
}

func (tree segtree) build(node int, v []int64, l, r int) {
	tree[node] = &segtreenode{
		node: node, l: l, r: r,
	}

	if l == r {
		tree[node].min = v[l]
		return
	}

	m := l + (r-l)/2
	tree.build(2*node+1, v, l, m)
	tree.build(2*node+2, v, m+1, r)

	tree[node].min = min(tree[2*node+1].min, tree[2*node+2].min)
}

func (tree segtree) getMin(node, l, r int) int64 {
	if l <= tree[node].l && tree[node].r <= r {
		return tree[node].min
	}

	nextNode := 2*node + 1
	if l > tree[node].l+(tree[node].r-tree[node].l)/2 {
		nextNode++
	}

	return tree.getMin(nextNode, l, r)
}

func min(nums ...int64) int64 {
	mn := nums[0]
	for _, x := range nums {
		if mn > x {
			mn = x
		}
	}
	return mn
}

package main

import (
	"bufio"
	"fmt"
	"os"
	"sort"
)

const inf int = 4*int(1e8) + 1

func solveForCurrentAndPrevious(curr, prev []int, notok [][]int) {
	seg := newSegtree(prev)

	for i := range curr {
		prevIdx := 0
		ans := inf

		for j := range notok[i] {
			currIdx := notok[i][j]

			if prevIdx <= currIdx-1 {
				ans = min(ans, seg.getMin(0, prevIdx, currIdx-1))
			}

			prevIdx = currIdx + 1
		}

		if prevIdx < len(prev) {
			ans = min(ans, seg.getMin(0, prevIdx, len(prev)-1))
		}

		if ans != inf {
			curr[i] = ans + curr[i]
		} else {
			curr[i] = inf
		}
	}
}

func solveE(a [4][]int, notok [3][][]int) {
	for i := 0; i < 3; i++ {
		prev, curr, notok := a[i], a[i+1], notok[i]
		solveForCurrentAndPrevious(curr, prev, notok)
	}

	ans := inf
	for i := range a[3] {
		ans = min(ans, a[3][i])
	}

	if ans == inf {
		ans = -1
	}

	printf("%d", ans)
}

func main() {
	defer writer.Flush()
	//redirectInputToFile(reader, "input.txt")

	T := 1
	// scan(&T)

	for t := 0; t < T; t++ {
		var n [4]int
		for i := range n {
			scan(&n[i])
		}

		var a [4][]int
		for i := range n {
			a[i] = make([]int, n[i])
			for j := range a[i] {
				scan(&a[i][j])
			}
		}

		var m [3]int
		var notok [3][][]int
		for i := range m {
			notok[i] = make([][]int, n[i+1])
			scan(&m[i])
			for j := 0; j < m[i]; j++ {
				u, v := 0, 0
				scan(&u, &v)
				notok[i][v-1] = append(notok[i][v-1], u-1)
			}
			for j := range notok[i] {
				arr := notok[i][j]
				sort.Slice(arr, func(i, j int) bool { return arr[i] < arr[j] })
			}
		}

		solveE(a, notok)
	}
}

var reader *bufio.Reader = bufio.NewReader(os.Stdin)
var writer *bufio.Writer = bufio.NewWriter(os.Stdout)

func scan(a ...interface{})             { fmt.Fscan(reader, a...) }
func printf(f string, a ...interface{}) { fmt.Fprintf(writer, f, a...) }

func redirectInputToFile(r *bufio.Reader, fp string) {
	f, err := os.Open(fp)
	if err != nil {
		panic(err)
	}
	r.Reset(f)
}

// ------------------

type segtree []*segtreenode

type segtreenode struct {
	node, l, r int
	segtreedata
}

type segtreedata struct {
	min int
}

func newSegtree(v []int) *segtree {
	tr := make(segtree, 4*len(v))
	tr.build(0, v, 0, len(v)-1)
	return &tr
}

func (tree segtree) build(node int, v []int, l, r int) {
	tree[node] = &segtreenode{
		node: node, l: l, r: r,
	}

	if l == r {
		tree[node].min = v[l]
		return
	}

	m := l + (r-l)/2
	tree.build(2*node+1, v, l, m)
	tree.build(2*node+2, v, m+1, r)

	tree[node].min = min(tree[2*node+1].min, tree[2*node+2].min)
}

func (tree segtree) getMin(node, l, r int) int {
	if l <= tree[node].l && tree[node].r <= r {
		return tree[node].min
	}

	nextNode := 2*node + 1
	if l > tree[node].l+(tree[node].r-tree[node].l)/2 {
		nextNode++
	}

	return tree.getMin(nextNode, l, r)
}

func min(nums ...int) int {
	mn := nums[0]
	for _, x := range nums {
		if mn > x {
			mn = x
		}
	}
	return mn
}