int main(){ #ifdef LOCAL freopen("/Users/apple/input.txt", "r", stdin); // freopen("/Users/apple/out.txt", "w", stdout); #endif while(si(n) != EOF) { rep(i, n) si(a[i]); minST.build(a, n, MIN); gcdST.build(a, n, GCD); int l = 1, r = n + 1, mid; while(l < r) { mid = (l + r) >> 1; if(check(mid)) l = mid + 1; else r = mid; } int len = l - 1; VI tmp; for(int i = 0; i + len <= n; i ++) { int j = i + len - 1; if(minST.query(i, j) == gcdST.query(i, j)) tmp.pb(i); } int sz = tmp.size(); printf("%d %d\n",sz, len - 1); rep(i, sz - 1) printf("%d ", tmp[i] + 1); put(tmp[sz-1] + 1); } return 0; }
// Imp bool check(int L) { for(int i = 0; i + L <= n; i ++) { int j = i + L - 1; if(minST.query(i, j) == gcdST.query(i, j)) return true; } return false; }
/// For each cell, order the (cell) neighbours counterclockwise. /// \param[in] grid A 2d grid object. /// \param[in, out] nb A cell-cell neighbourhood table, such as from cellNeighboursAcrossVertices(). void orderCounterClockwise(const UnstructuredGrid& grid, SparseTable<int>& nb) { if (grid.dimensions != 2) { OPM_THROW(std::logic_error, "Cannot use orderCounterClockwise in " << grid.dimensions << " dimensions."); } const int num_cells = grid.number_of_cells; if (nb.size() != num_cells) { OPM_THROW(std::logic_error, "Inconsistent arguments for orderCounterClockwise()."); } // For each cell, compute each neighbour's angle with the x axis, // sort that to find the correct permutation of the neighbours. typedef std::pair<double, int> AngleAndPos; std::vector<AngleAndPos> angle_and_pos; std::vector<int> original; for (int cell = 0; cell < num_cells; ++cell) { const int num_nb = nb[cell].size(); angle_and_pos.clear(); angle_and_pos.resize(num_nb); for (int ii = 0; ii < num_nb; ++ii) { const int cell2 = nb[cell][ii]; const double v[2] = { grid.cell_centroids[2*cell2] - grid.cell_centroids[2*cell], grid.cell_centroids[2*cell2 + 1] - grid.cell_centroids[2*cell + 1] }; // The formula below gives an angle in [0, 2*pi] with the positive x axis. const double angle = boost::math::constants::pi<double>() - std::atan2(v[1], -v[0]); angle_and_pos[ii] = std::make_pair(angle, ii); } original.assign(nb[cell].begin(), nb[cell].end()); std::sort(angle_and_pos.begin(), angle_and_pos.end()); for (int ii = 0; ii < num_nb; ++ii) { nb[cell][ii] = original[angle_and_pos[ii].second]; } } }
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; }
/// Solve for time-of-flight and a number of tracers. /// \param[in] darcyflux Array of signed face fluxes. /// \param[in] porevolume Array of pore volumes. /// \param[in] source Source term. Sign convention is: /// (+) inflow flux, /// (-) outflow flux. /// \param[in] tracerheads Table containing one row per tracer, and each /// row contains the source cells for that tracer. /// \param[out] tof Array of time-of-flight values (1 per cell). /// \param[out] tracer Array of tracer values. N per cell, where N is /// equalt to tracerheads.size(). void TofReorder::solveTofTracer(const double* darcyflux, const double* porevolume, const double* source, const SparseTable<int>& tracerheads, std::vector<double>& tof, std::vector<double>& tracer) { darcyflux_ = darcyflux; porevolume_ = porevolume; source_ = source; const int num_cells = grid_.number_of_cells; #ifndef NDEBUG // Sanity check for sources. const double cum_src = std::accumulate(source, source + num_cells, 0.0); if (std::fabs(cum_src) > *std::max_element(source, source + num_cells)*1e-2) { OPM_THROW(std::runtime_error, "Sources do not sum to zero: " << cum_src); } #endif tof.resize(num_cells); std::fill(tof.begin(), tof.end(), 0.0); tof_ = &tof[0]; if (use_multidim_upwind_) { face_tof_.resize(grid_.number_of_faces); std::fill(face_tof_.begin(), face_tof_.end(), 0.0); face_part_tof_.resize(grid_.face_nodepos[grid_.number_of_faces]); std::fill(face_part_tof_.begin(), face_part_tof_.end(), 0.0); } // Execute solve for tof compute_tracer_ = false; executeSolve(); // Find the tracer heads (injectors). const int num_tracers = tracerheads.size(); tracer.resize(num_cells*num_tracers); std::fill(tracer.begin(), tracer.end(), 0.0); if (num_tracers > 0) { tracerhead_by_cell_.clear(); tracerhead_by_cell_.resize(num_cells, NoTracerHead); } for (int tr = 0; tr < num_tracers; ++tr) { for (int i = 0; i < tracerheads[tr].size(); ++i) { const int cell = tracerheads[tr][i]; tracer[num_cells * tr + cell] = 1.0; tracerhead_by_cell_[cell] = tr; } } // Execute solve for tracers. std::vector<double> fake_pv(num_cells, 0.0); porevolume_ = fake_pv.data(); for (int tr = 0; tr < num_tracers; ++tr) { tof_ = tracer.data() + tr * num_cells; compute_tracer_ = true; executeSolve(); } // Write output tracer data (transposing the computed data). std::vector<double> computed = tracer; for (int cell = 0; cell < num_cells; ++cell) { for (int tr = 0; tr < num_tracers; ++tr) { tracer[num_tracers * cell + tr] = computed[num_cells * tr + cell]; } } }
// 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; }
void initialize(vui_t const& elems) { len = elems.size(); if (len < MIN_SIZE_FOR_BENDER_RMQ) { st.initialize(elems); return; } vui_t levels; SimpleFixedObjectAllocator<BinaryTreeNode> alloc(len); euler.reserve(elems.size() * 2); mapping.resize(elems.size()); BinaryTreeNode *root = make_cartesian_tree(elems, alloc); DPRINTF("GraphViz (paste at: http://ashitani.jp/gv/):\n%s\n", toGraphViz(NULL, root).c_str()); euler_tour(root, euler, levels, mapping, rev_mapping); root = NULL; // This tree has now been deleted alloc.clear(); assert_eq(levels.size(), euler.size()); assert_eq(levels.size(), rev_mapping.size()); uint_t n = euler.size(); lgn_by_2 = log2(n) / 2; _2n_lgn = n / lgn_by_2 + 1; DPRINTF("n = %u, lgn/2 = %d, 2n/lgn = %d\n", n, lgn_by_2, _2n_lgn); lt.initialize(lgn_by_2); table_map.resize(_2n_lgn); vui_t reduced; for (uint_t i = 0; i < n; i += lgn_by_2) { uint_t max_in_block = euler[i]; int bitmap = 1L; DPRINTF("Sequence: (%u, ", euler[i]); for (int j = 1; j < lgn_by_2; ++j) { int curr_level, prev_level; uint_t value; if (i+j < n) { curr_level = levels[i+j]; prev_level = levels[i+j-1]; value = euler[i+j]; } else { curr_level = 1; prev_level = 0; value = 0; } const uint_t bit = (curr_level < prev_level); bitmap |= (bit << j); max_in_block = std::max(max_in_block, value); DPRINTF("%u, ", value); } DPRINTF("), Bitmap: %s\n", bitmap_str(bitmap).c_str()); table_map[i / lgn_by_2] = bitmap; reduced.push_back(max_in_block); } DPRINTF("reduced.size(): %u\n", reduced.size()); st.initialize(reduced); DCERR("initialize() completed"<<endl); }