class TheGridDivTwo(object):
    seen = set()
    invalid = set()
    Q = Queue()
    bestX = None

    def find1(self, x, y, k):
        self.seen = set()
        self.invalid = set()
        self.Q = Queue()
        self.bestX = 0
        # hash each invalid position
        for i in range(len(x)):
            self.invalid.add((x[i], y[i]))

        # dbfs for the highest y position reachable
        self.Q.put( (0, 0, k) )
        while not self.Q.empty():
            x, y, ttl = self.Q.get_nowait()
            self.bestX = max(self.bestX, x)
            if ttl == 0:
                continue 
            for newPos in ( (x, y-1), (x, y+1), (x-1, y), (x+1, y) ):
                if newPos in self.seen:
                    continue
                if newPos in self.invalid:
                    continue
                else:
                    self.seen.add(newPos)
                    self.Q.put( ( newPos[0], newPos[1], ttl-1 ) )
        return self.bestX            

    # same as find1, but does not use python Queue.Queue
    def find2(self, x, y, k):
        self.seen = set()
        self.invalid = set()
        self.Q = deque()
        self.bestX = 0
        # hash each invalid position
        for i in range(len(x)):
            self.invalid.add((x[i], y[i]))

        self.Q.append( (0, 0, k) ) #appends to right of deque
        while len(self.Q) != 0:
            x, y, ttl = self.Q.popleft()
            self.bestX = max(self.bestX, x)
            if ttl == 0:
                continue 
            for newPos in ( (x, y-1), (x, y+1), (x-1, y), (x+1, y) ):
                if newPos in self.seen or newPos in self.invalid:
                    continue
                else:
                    self.seen.add(newPos)
                    self.Q.append( ( newPos[0], newPos[1], ttl-1 ) )
        return self.bestX            


    # same as find1/2, but uses a huge list instead of a Queue
    def find3(self, x, y, k):
        self.seen = set()
        self.invalid = set()

        Q = [ 0 ] * (((2*k+1)**2)+1)
        Qstart = 0
        Qend = 0

        self.bestX = 0
        # hash each invalid position
        for i in range(len(x)):
            self.invalid.add((x[i], y[i]))

        Q[Qend] = ( (0, 0, k) )
        Qend += 1
        while Qstart < Qend:
            x, y, ttl = Q[Qstart]
            Qstart += 1
            self.bestX = max(self.bestX, x)
            if ttl == 0:
                continue 
            for newPos in ( (x, y-1), (x, y+1), (x-1, y), (x+1, y) ):
                if newPos in self.seen or newPos in self.invalid:
                    continue
                else:
                    self.seen.add(newPos)
                    Q[Qend] = ( ( newPos[0], newPos[1], ttl-1 ) )
                    Qend += 1
        return self.bestX            



    def find(self, x, y, k):
        return self.find2(x, y, k)