int test() { printf("Testing SparseTable implementation\n"); printf("----------------------------------\n"); vui_t v; v.push_back(45); v.push_back(4); v.push_back(5); v.push_back(2); v.push_back(99); v.push_back(41); v.push_back(45); v.push_back(45); v.push_back(51); v.push_back(89); v.push_back(1); v.push_back(3); v.push_back(5); v.push_back(98); for (int i = 0; i < 10; ++i) { // printf("%d: %d\n", i, log2(i)); } SparseTable st; st.initialize(v); for (size_t i = 0; i < v.size(); ++i) { for (size_t j = i; j < v.size(); ++j) { pui_t one = st.query_max(i, j); pui_t two = naive_query_max(v, i, j); printf("query_max(%u, %u) == (%u, %u)\n", (uint_t)i, (uint_t)j, one.first, two.first); assert_eq(one.first, two.first); } } printf("\n"); return 0; }
// qf & ql are indexes; both inclusive. // Return: first -> value, second -> index pui_t query_max(uint_t qf, uint_t ql) { if (qf >= this->len || ql >= this->len || ql < qf) { return make_pair(minus_one, minus_one); } if (len < MIN_SIZE_FOR_BENDER_RMQ) { return st.query_max(qf, ql); } DPRINTF("[1] (qf, ql) = (%d, %d)\n", qf, ql); // Map to +-RMQ co-ordinates qf = mapping[qf]; ql = mapping[ql]; DPRINTF("[2] (qf, ql) = (%d, %d)\n", qf, ql); if (qf > ql) { std::swap(qf, ql); DPRINTF("[3] (qf, ql) = (%d, %d)\n", qf, ql); } // Determine whether we need to query 'st'. const uint_t first_block_index = qf / lgn_by_2; const uint_t last_block_index = ql / lgn_by_2; DPRINTF("first_block_index: %u, last_block_index: %u\n", first_block_index, last_block_index); pui_t ret(0, 0); /* Main logic: * * [1] If the query is restricted to a single block, then * first_block_index == last_block_index, and we only need to * do a bitmap based lookup. * * [2] If last_block_index - first_block_index == 1, then the * query spans 2 blocks, and we do not need to lookup the * Sparse Table to get the summary max. * * [3] In all other cases, we need to take the maximum of 3 * results, (a) the max in the suffix of the first block, (b) * the max in the prefix of the last block, and (c) the max of * all blocks between the first and the last block. * */ if (last_block_index - first_block_index > 1) { // We need to perform an inter-block query using the 'st'. ret = st.query_max(first_block_index + 1, last_block_index - 1); // Now perform an in-block query to get the index of the // max value as it appears in 'euler'. const uint_t bitmapx = table_map[ret.second]; const uint_t imax = lt.query_max(bitmapx, 0, lgn_by_2-1) + ret.second*lgn_by_2; ret.second = imax; } else if (first_block_index == last_block_index) { // The query is completely within a block. const uint_t bitmapx = table_map[first_block_index]; DPRINTF("bitmapx: %s\n", bitmap_str(bitmapx).c_str()); qf %= lgn_by_2; ql %= lgn_by_2; const uint_t imax = lt.query_max(bitmapx, qf, ql) + first_block_index*lgn_by_2; ret = make_pair(euler[imax], rev_mapping[imax]); return ret; } // Now perform an in-block query for the first and last // blocks. const uint_t f1 = qf % lgn_by_2; const uint_t f2 = lgn_by_2 - 1; const uint_t l1 = 0; const uint_t l2 = ql % lgn_by_2; const uint_t bitmap1 = table_map[first_block_index]; const uint_t bitmap2 = table_map[last_block_index]; DPRINTF("bitmap1: %s, bitmap2: %s\n", bitmap_str(bitmap1).c_str(), bitmap_str(bitmap2).c_str()); uint_t max1i = lt.query_max(bitmap1, f1, f2); uint_t max2i = lt.query_max(bitmap2, l1, l2); DPRINTF("max1i: %u, max2i: %u\n", max1i, max2i); max1i += first_block_index * lgn_by_2; max2i += last_block_index * lgn_by_2; if (last_block_index - first_block_index > 1) { // 3-way max DPRINTF("ret: %u, max1: %u, max2: %u\n", ret.first, euler[max1i], euler[max2i]); if (ret.first > euler[max1i] && ret.first > euler[max2i]) { ret.second = rev_mapping[ret.second]; } else if (euler[max1i] >= ret.first && euler[max1i] >= euler[max2i]) { ret = make_pair(euler[max1i], rev_mapping[max1i]); } else if (euler[max2i] >= ret.first && euler[max2i] >= euler[max1i]) { ret = make_pair(euler[max2i], rev_mapping[max2i]); } } else { // 2-way max if (euler[max1i] > euler[max2i]) { ret = make_pair(euler[max1i], rev_mapping[max1i]); } else { ret = make_pair(euler[max2i], rev_mapping[max2i]); } } return ret; }