# Arup Guha
# 4/27/2025
# Solution to COP 4516 Team Final Contest Problem: Lighting Fuses

# Resets all elements in arr to val.
def reset(arr, val):
    for i in range(len(arr)):
        arr[i] = val

class ff:

    # Create an empty flow graph of size sz (source, sink added later).
    def __init__(self, sz):

        # Basic set up.
        self.n = sz + 2
        self.source = self.n - 2
        self.sink = self.n - 1
        self.cap = []

        # Initialize all capacities to 0.
        for i in range(self.n):

            tmp = []
            for j in range(self.n):
                tmp.append(0)

            self.cap.append(tmp)

    # Sets capacity from v1 to v2 of c.
    def add(self, v1, v2, c):
        self.cap[v1][v2] = c

    def dfs(self, v, visited, minF):

        # Made it to end with minF flow.
        if v == self.sink:
            return minF

        # Been here before, can't go again.
        if visited[v]:
            return 0

        # Mark it and start trying to go elsewhere.
        visited[v] = True
        maxflow = 0
        
        # Due to our inefficient storage, we just do it this way.
        for i in range(self.n):

            # We can push some flow in this direction.
            if self.cap[v][i] > 0:
                maxflow = self.dfs(i, visited, min(self.cap[v][i], minF))

            # We got all the way through!
            if maxflow > 0:

                # Reduce flow in this forward direction.
                self.cap[v][i] -= maxflow

                # Which means the backwards capacity increases.
                self.cap[i][v] += maxflow

                # Great, return it.
                return maxflow

        return 0

    # Returns the max flow of this object.
    def flow(self):

        # Reset if flows will be larger than this.
        INF = 1000000000

        # Set up visited array for DFS.
        visited = []
        for i in range(self.n):
            visited.append(False)

        maxflow = 0

        # We'll break out...
        while True:

            # Try augmenting.
            reset(visited, False)
            res = self.dfs(self.source, visited, INF)

            # No augmenting path.
            if res == 0:
                break

            # Add it.
            maxflow += res

        return maxflow

# Returns true if this matching works.
def canDo(nFuses, nFire, burn, match, maxT):

    # Left end has nodes for each fuse, right side for each firework and one dummy node
    # for fuses that aren't matched.
    g = ff(nFuses+nFire+1)

    # So I can remember easier.
    sourceID = nFuses + nFire + 1
    sinkID = sourceID + 1

    # Link from source to each fuse.
    for i in range(nFuses):
        g.add(sourceID, i, 1)

    # Link from each firework to the sink.
    for i in range(nFuses, nFuses+nFire):
        g.add(i, sinkID, 1)

    # Must have the exact right dummy node capacity.
    g.add(nFuses+nFire, sinkID, nFuses-nFire)

    # These burn fast enough on their own link to dummy.
    for i in range(nFuses):
        if burn[i] <= maxT:
            g.add(i, nFuses+nFire, 1)

    # If a fuse/firework match goes fast enough, add the appropriate edge.
    for i in range(len(match)):
        for j in range(len(match[i])):
            if match[i][j] <= maxT:
                g.add(j, nFuses+i, 1)

    # Run it!
    tot = g.flow()

    # Success if each fuse is matched.
    return tot == nFuses

# Start main here.
def main():

    # Process cases.
    nC = int(input())
    for loop in range(nC):

        # Get number of fuses and fireworks.
        toks = input().split()
        nFuses = int(toks[0])
        nFire = int(toks[1])

        # Get each fuse's burn time.
        burn = [int(x) for x in input().split()]

        # Set to store all possible answers.
        tVals = set()
        for x in burn:
            tVals.add(x)

        # Match numbers for fuse, firework.
        match = []
        for i in range(nFire):
            tmp = [int(x) for x in input().split()]
            match.append(tmp)
            for x in tmp:
                tVals.add(x)

        # We are binary searching on these values.
        listTVals = list(tVals)
        listTVals.sort()

        # Bounds for binary search.
        low = 0
        high = len(listTVals)-1
        
        # Run it.
        while low < high:

            mid = (low+high)//2

            if canDo(nFuses, nFire, burn, match, listTVals[mid]):
                high = mid
            else:
                low = mid+1

        # Here is our answer.
        print(listTVals[low])

# Run it!
main()


        
