結果
問題 |
No.2223 Merged Med
|
ユーザー |
![]() |
提出日時 | 2025-05-14 13:01:11 |
言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
結果 |
TLE
|
実行時間 | - |
コード長 | 11,939 bytes |
コンパイル時間 | 1,216 ms |
コンパイル使用メモリ | 97,568 KB |
実行使用メモリ | 7,848 KB |
最終ジャッジ日時 | 2025-05-14 13:03:02 |
合計ジャッジ時間 | 9,945 ms |
ジャッジサーバーID (参考情報) |
judge3 / judge5 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 3 |
other | AC * 10 TLE * 1 -- * 22 |
ソースコード
#include <iostream> #include <vector> #include <algorithm> #include <numeric> #include <map> #include <vector> // Ensure vector is included // Use long long for potentially large prefix sums and infinity constant using ValueType = long long; // Define a large value for infinity, suitable for long long const ValueType INF = 2e18; // Structure for segment tree nodes struct Node { // Stores the maximum P_i value within the node's range of prefix sum values. // Initialized to -INF to signify absence of value. ValueType max_val = -INF; }; // Global variables for segment tree implementation std::vector<Node> tree; // The segment tree array std::vector<ValueType> p_vals; // Stores unique prefix sum values for coordinate compression std::map<ValueType, int> p_to_idx; // Maps a prefix sum value to its compressed index /** * @brief Builds coordinate compression map for prefix sum values. * Sorts the unique prefix sum values and creates a mapping from each value to its rank (index). * @param P Vector of prefix sums. */ void build_coord_map(const std::vector<ValueType>& P) { p_vals.clear(); // Clear previous mapping data p_to_idx.clear(); std::vector<ValueType> temp_p = P; // Create a temporary copy to sort std::sort(temp_p.begin(), temp_p.end()); // Sort prefix sums to find unique values p_vals.reserve(P.size()); // Optimize vector capacity // Iterate through sorted values and add unique ones to p_vals for (ValueType val : temp_p) { if (p_vals.empty() || p_vals.back() != val) { p_vals.push_back(val); } } // Build the map from value to its index (rank) for (int i = 0; i < p_vals.size(); ++i) { p_to_idx[p_vals[i]] = i; } } /** * @brief Builds the segment tree structure recursively. * Initializes all nodes with default value (-INF). * @param node Current node index in the tree array. * @param start Start index of the segment covered by this node. * @param end End index of the segment covered by this node. */ void build(int node, int start, int end) { if (start > end) return; // Base case: invalid range tree[node] = {-INF}; // Initialize node's max_val if (start == end) { // Base case: leaf node return; } int mid = start + (end - start) / 2; // Calculate middle index build(2 * node, start, mid); // Recursively build left child build(2 * node + 1, mid + 1, end); // Recursively build right child } /** * @brief Updates the segment tree at a specific index with a new value. * The update sets the max_val at the leaf corresponding to `idx` to max(current_max, val). * Propagates the update up the tree. * @param node Current node index. * @param start Start index of the node's range. * @param end End index of the node's range. * @param idx The compressed index to update. * @param val The P_i value to potentially update with. */ void update(int node, int start, int end, int idx, ValueType val) { // Check if index is outside the current node's range if (start > end || idx < start || idx > end) return; if (start == end) { // Reached the leaf node corresponding to the index tree[node].max_val = std::max(tree[node].max_val, val); // Update max value return; } int mid = start + (end - start) / 2; // Calculate middle index // Recurse down to the appropriate child based on index if (idx <= mid) { update(2 * node, start, mid, idx, val); } else { update(2 * node + 1, mid + 1, end, idx, val); } // Update current node's max value based on its children's max values tree[node].max_val = std::max(tree[2 * node].max_val, tree[2 * node + 1].max_val); } /** * @brief Queries the maximum value in the segment tree over a given range [L, R]. * The range refers to compressed indices. * @param node Current node index. * @param start Start index of the node's range. * @param end End index of the node's range. * @param L Start index of the query range. * @param R End index of the query range. * @return Maximum P_i value found in the query range, or -INF if none found. */ ValueType query(int node, int start, int end, int L, int R) { // If query range is invalid or doesn't overlap with node's range if (start > end || R < start || end < L || L > R) { return -INF; // Return -INF indicating no value found } // If node's range is fully contained within query range if (L <= start && end <= R) { return tree[node].max_val; // Return this node's max value } int mid = start + (end - start) / 2; // Calculate middle index // Recursively query left and right children and return the maximum of results ValueType p1 = query(2 * node, start, mid, L, R); ValueType p2 = query(2 * node + 1, mid + 1, end, L, R); return std::max(p1, p2); } /** * @brief Check function to determine if the beauty of subarray A[L_query..R_query] is <= V. * Implements the logic derived using binary representation and prefix sums. * Uses a segment tree over coordinate compressed prefix sum values for efficient queries. * @param V The threshold value being tested. * @param A The original array. * @param L_query Start index of the query subarray (1-based). * @param R_query End index of the query subarray (1-based). * @return True if beauty <= V, False otherwise. */ bool check(int V, const std::vector<int>& A, int L_query, int R_query) { int k = R_query - L_query + 1; // Length of the subarray // Constraints state 1 <= L <= R <= N, so k >= 1. The k <= 0 case is not needed. // Calculate prefix sums P based on threshold V std::vector<ValueType> P(k + 1, 0); // P[0] = 0 ValueType current_S = 0; for (int i = 0; i < k; ++i) { // Convert A element to 1 if <= V, else -1 int val = (A[L_query + i - 1] <= V) ? 1 : -1; // Adjust to 0-based index for A current_S += val; // Update the running sum P[i + 1] = current_S; // Store prefix sum P[i+1] } ValueType S = P[k]; // The total sum S = P_k // Perform coordinate compression on prefix sum values build_coord_map(P); int map_size = p_vals.size(); // Number of unique prefix sum values // If map_size is 0, means P was empty or had only one identical value. // Should not happen for k >= 1, as P will have at least P[0]=0 and P[1]. if (map_size == 0) { return true; // Fallback, should not be reached under problem constraints. } // Initialize segment tree with appropriate size (4*map_size is safe) tree.assign(4 * map_size + 4, {-INF}); build(1, 0, map_size - 1); // Build the tree structure ValueType M = INF; // Initialize minimum value M = min f(T) to positive infinity // Insert P_0 = 0 into the segment tree using its compressed index update(1, 0, map_size - 1, p_to_idx[P[0]], P[0]); // Iterate through j from 1 to k for (int j = 1; j <= k; ++j) { ValueType Pj = P[j]; // Current prefix sum P_j // Case 1: Check subsegments where median <= V. Requires finding max P_i s.t. i < j and P_i <= P_j - 1. int idx_le_Pj_minus_1 = -1; // Find the largest compressed index `idx` such that `p_vals[idx] <= Pj - 1`. auto it_le = std::upper_bound(p_vals.begin(), p_vals.end(), Pj - 1); // If `it_le` is not the beginning, means there exists at least one element <= Pj - 1. if (it_le != p_vals.begin()) { idx_le_Pj_minus_1 = std::distance(p_vals.begin(), it_le) - 1; } ValueType max_Pi_le = -INF; // Max P_i found for Case 1 if (idx_le_Pj_minus_1 != -1) { // If a valid index range exists // Query segment tree for max P_i in the range [0, idx_le_Pj_minus_1] max_Pi_le = query(1, 0, map_size - 1, 0, idx_le_Pj_minus_1); } // If a valid P_i was found (value > -INF) if (max_Pi_le > -INF) { ValueType T = Pj - max_Pi_le; // Calculate difference T = P_j - P_i if (T >= 1) { // Check condition for Case 1: T >= 1 ValueType current_f = T; // Calculate f(T) = T for T >= 1 M = std::min(M, current_f); // Update overall minimum M } } // Case 2: Check subsegments where median > V. Requires finding max P_i s.t. i < j and P_i >= P_j. int idx_ge_Pj = -1; // Find the smallest compressed index `idx` such that `p_vals[idx] >= Pj`. auto it_ge = std::lower_bound(p_vals.begin(), p_vals.end(), Pj); // If `it_ge` is not the end iterator, means there exists at least one element >= Pj. if (it_ge != p_vals.end()) { idx_ge_Pj = std::distance(p_vals.begin(), it_ge); } ValueType max_Pi_ge = -INF; // Max P_i found for Case 2 if (idx_ge_Pj != -1 && idx_ge_Pj < map_size) { // Check if index is valid and within bounds // Query segment tree for max P_i in range [idx_ge_Pj, map_size - 1] max_Pi_ge = query(1, 0, map_size - 1, idx_ge_Pj, map_size - 1); } // If a valid P_i was found (value > -INF) if (max_Pi_ge > -INF) { ValueType T = Pj - max_Pi_ge; // Calculate difference T = P_j - P_i if (T <= 0) { // Check condition for Case 2: T <= 0 ValueType current_f = T + 2; // Calculate f(T) = T + 2 for T <= 0 M = std::min(M, current_f); // Update overall minimum M } } // Update segment tree with P_j's value `Pj` at its compressed index `p_to_idx[Pj]`. // This makes Pj available as a potential P_i for future iterations j' > j. if (p_to_idx.count(Pj)) { // Check if Pj is in the map (it should be) update(1, 0, map_size - 1, p_to_idx[Pj], Pj); } else { // This branch indicates an error/bug since Pj must be in the map. } } // After loop, M holds the minimum value of f(T) over all subsegments [l..r]. // If M is still INF, it means no valid subsegment was processed or updated M. // This should not happen for k >= 1. if (M == INF) { // If k >= 1, M should be finite. This indicates an issue or unhandled edge case. // Defaulting to true might be safer than possibly incorrect false. return true; } // Final condition check: Total sum S must be >= Minimum value M found. return S >= M; } int main() { std::ios_base::sync_with_stdio(false); // Use faster I/O std::cin.tie(NULL); // Untie cin and cout streams int N, Q; // Read number of elements N and number of queries Q std::cin >> N >> Q; std::vector<int> A(N); // Declare vector A of size N // Read elements of array A for (int i = 0; i < N; ++i) { std::cin >> A[i]; } // Process Q queries for (int q = 0; q < Q; ++q) { int L, R; // Read query range [L, R] (1-based indices) std::cin >> L >> R; // Binary search for the minimum possible median value (the "beauty") // The beauty must be one of the values in A, so search range is [1, N]. int low = 1, high = N, ans = N + 1; // Initialize answer to a value outside range [1, N] while(low <= high) { // Standard binary search loop int mid = low + (high - low) / 2; // Calculate midpoint value to test // Check if the beauty can be less than or equal to `mid` if (check(mid, A, L, R)) { ans = mid; // If yes, `mid` is a possible answer, try smaller values high = mid - 1; } else { // If no, `mid` is too small, need a larger value low = mid + 1; } } // Output the minimum value found (the beauty) std::cout << ans << "\n"; } return 0; // Indicate successful execution }