結果

問題 No.2223 Merged Med
ユーザー qwewe
提出日時 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
権限があれば一括ダウンロードができます

ソースコード

diff #

#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
}
0