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 (
	. "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)
	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(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 (
	"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
}