def preprocess(self, A): self.n = len(A) self.A = A self.b_size = int(math.log(self.n, 2)/2) + 1 self.blocks = [] # list of minimums for each block of size b_size self.where = [] # keeps the index of the minimum of the block self.blocks_ids = {} self.norm_b = [] self.b_unique = [] # keeps a map between block position # and its normalized index, dont need to be a map smaller = A[0] block = [A[0]] smaller_id = 0 for i in xrange(1, self.n): if len(block) == self.b_size: self.blocks.append(smaller) self.where.append(smaller_id) b_id = self.preprocess_blocks(block) self.b_unique.append(b_id) block = [A[i]] smaller = A[i] smaller_id = i else: block.append(A[i]) if smaller > A[i]: smaller = A[i] smaller_id = i self.blocks.append(smaller) self.where.append(smaller_id) b_id = self.preprocess_blocks(block) self.b_unique.append(b_id) assert len(self.blocks) == (self.n - 1)/self.b_size + 1 assert len(self.blocks) == len(self.where) self.rmq_st = RMQSt() self.rmq_st.preprocess(self.blocks)
class RMQRestrict: def __init__(self): pass """ Normalizes block and memorizes all solutions for this block. Returns a b_id which can be used to retrive solutions in this block. It is important to remember that the solutions inside a block is an 0-based index. """ def preprocess_blocks(self, block): nblock = [0]*len(block) for j in xrange(1, len(block)): nblock[j] = block[j] - block[j - 1] if self.blocks_ids.has_key(tuple(nblock)): return self.blocks_ids[tuple(nblock)] else: b_id = len(self.blocks_ids) self.blocks_ids[tuple(nblock)] = b_id m_ij = {} for i in xrange(len(block)): smaller = i for j in xrange(i, len(block)): if block[smaller] > block[j]: smaller = j m_ij[i, j] = smaller self.norm_b.append(m_ij) assert len(self.norm_b) == len(self.blocks_ids) return b_id def preprocess(self, A): self.n = len(A) self.A = A self.b_size = int(math.log(self.n, 2)/2) + 1 self.blocks = [] # list of minimums for each block of size b_size self.where = [] # keeps the index of the minimum of the block self.blocks_ids = {} self.norm_b = [] self.b_unique = [] # keeps a map between block position # and its normalized index, dont need to be a map smaller = A[0] block = [A[0]] smaller_id = 0 for i in xrange(1, self.n): if len(block) == self.b_size: self.blocks.append(smaller) self.where.append(smaller_id) b_id = self.preprocess_blocks(block) self.b_unique.append(b_id) block = [A[i]] smaller = A[i] smaller_id = i else: block.append(A[i]) if smaller > A[i]: smaller = A[i] smaller_id = i self.blocks.append(smaller) self.where.append(smaller_id) b_id = self.preprocess_blocks(block) self.b_unique.append(b_id) assert len(self.blocks) == (self.n - 1)/self.b_size + 1 assert len(self.blocks) == len(self.where) self.rmq_st = RMQSt() self.rmq_st.preprocess(self.blocks) def get_block_and_index(self, i): block_i = i/self.b_size index_i = i%self.b_size return (block_i, index_i) def query(self, i, j): assert i <= j block_i, index_i = self.get_block_and_index(i) block_j, index_j = self.get_block_and_index(j) # WARNING: change me later, ineficient if block_i != block_j: ans_value = self.A[i] ans_index = i if block_i + 1 < block_j: bid = self.rmq_st.query(block_i + 1, block_j - 1) ans_value = self.blocks[bid] ans_index = self.where[bid] id_bi = self.b_unique[block_i] id_bj = self.b_unique[block_j] id_min_in_bi = block_i * self.b_size + \ self.norm_b[id_bi][index_i, self.b_size - 1] id_min_in_bj = block_j * self.b_size + \ self.norm_b[id_bj][0, index_j] if self.A[id_min_in_bi] < ans_value: ans_value = self.A[id_min_in_bi] ans_index = id_min_in_bi if self.A[id_min_in_bj] < ans_value: ans_value = self.A[id_min_in_bj] ans_index = id_min_in_bj return ans_index else: b_id = self.b_unique[block_i] id_min = block_i * self.b_size + \ self.norm_b[b_id][index_i, index_j] return id_min