結果

問題 No.1394 Changing Problems
ユーザー qwewe
提出日時 2025-05-14 13:14:59
言語 C++17
(gcc 13.3.0 + boost 1.87.0)
結果
WA  
実行時間 -
コード長 11,344 bytes
コンパイル時間 758 ms
コンパイル使用メモリ 86,668 KB
実行使用メモリ 32,972 KB
最終ジャッジ日時 2025-05-14 13:16:02
合計ジャッジ時間 7,401 ms
ジャッジサーバーID
(参考情報)
judge5 / judge3
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 3
other AC * 24 WA * 5
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <iostream>
#include <vector>
#include <numeric>
#include <algorithm>
#include <limits> // Required for numeric_limits

using namespace std;

// Define long long type for potentially large numbers
typedef long long ll;

// Use standard limits for min/max identity elements for segment trees
const ll LL_INF = numeric_limits<ll>::max();
// Use a sufficiently small value for negative infinity to avoid overflow issues
// Any value smaller than minimum possible A_i - (N-2) is okay.
const ll LL_NEG_INF = -4e18; 

// Segment Tree node structure for Range Maximum Query
// Used to efficiently find T_max = max(0, max_i(A_i - (N-2)))
struct MaxSegTreeNode {
    ll max_val = LL_NEG_INF; // Initialize with smallest possible value
};

vector<MaxSegTreeNode> max_seg_tree; // Segment tree array for T_max
vector<ll> A_for_Tmax; // Stores A_i - (N-2) values for leaf nodes

// Build the segment tree for T_max
void build_max_tree(int node, int start, int end) {
    if (start == end) {
        // Leaf node corresponds to an element A_i - (N-2)
        if (start < A_for_Tmax.size()) {
             max_seg_tree[node].max_val = A_for_Tmax[start];
        }
    } else {
        int mid = start + (end - start) / 2;
        build_max_tree(2 * node, start, mid);
        build_max_tree(2 * node + 1, mid + 1, end);
        // Internal node stores the maximum of its children
        max_seg_tree[node].max_val = max(max_seg_tree[2 * node].max_val, max_seg_tree[2 * node + 1].max_val);
    }
}

// Update a value in the segment tree for T_max
void update_max_tree(int node, int start, int end, int idx, ll val) {
    // Check if index is within node's range
     if (start > idx || end < idx) return; 
    if (start == end) {
        // Update leaf node value
        max_seg_tree[node].max_val = val;
    } else {
        int mid = start + (end - start) / 2;
        // Recurse down to the correct child
        if (idx <= mid) { 
            update_max_tree(2 * node, start, mid, idx, val);
        } else {
            update_max_tree(2 * node + 1, mid + 1, end, idx, val);
        }
        // Update internal node value based on children
        max_seg_tree[node].max_val = max(max_seg_tree[2 * node].max_val, max_seg_tree[2 * node + 1].max_val);
    }
}

// Query the maximum value in a range [l, r] in the segment tree for T_max
ll query_max_tree(int node, int start, int end, int l, int r) {
    // Check for invalid range or range outside node's responsibility
     if (r < start || end < l || l > r) { 
        return LL_NEG_INF; // Return identity element for max
    }
    // If node's range is fully contained within query range
    if (l <= start && end <= r) {
        return max_seg_tree[node].max_val;
    }
    // Recurse down to children
    int mid = start + (end - start) / 2;
    ll p1 = query_max_tree(2 * node, start, mid, l, r);
    ll p2 = query_max_tree(2 * node + 1, mid + 1, end, l, r);
    // Combine results from children
    return max(p1, p2);
}


// Segment Tree node structure for Range Add and Range Minimum Query
// Used to efficiently find min M(r) = min (K * sum_p + f(r)) where f(r) = (K+1)r - K S_r
struct MinSegTreeNode {
    ll min_val = LL_INF; // Initialize with largest possible value
    ll lazy = 0; // Lazy tag for range updates
};

vector<MinSegTreeNode> min_seg_tree; // Segment tree array for f(r) values
vector<ll> initial_f_values; // Stores initial f(r) values for leaf nodes

// Push lazy updates down to children
void push(int node, int start, int end) { 
     if (min_seg_tree[node].lazy != 0 && start != end) { // Only push if not a leaf and lazy tag exists
        // Apply lazy tag to children's min_val and lazy tag
        min_seg_tree[2 * node].min_val += min_seg_tree[node].lazy;
        min_seg_tree[2 * node].lazy += min_seg_tree[node].lazy;
        min_seg_tree[2 * node + 1].min_val += min_seg_tree[node].lazy;
        min_seg_tree[2 * node + 1].lazy += min_seg_tree[node].lazy;
        // Clear current node's lazy tag
        min_seg_tree[node].lazy = 0;
    }
}

// Build the segment tree for f(r) values
void build_min_tree(int node, int start, int end) {
    if (start == end) {
        // Leaf node corresponds to an initial f(r) value
         if (start < initial_f_values.size()) {
              min_seg_tree[node].min_val = initial_f_values[start];
         } 
    } else {
        int mid = start + (end - start) / 2;
        build_min_tree(2 * node, start, mid);
        build_min_tree(2 * node + 1, mid + 1, end);
        // Internal node stores the minimum of its children
        min_seg_tree[node].min_val = min(min_seg_tree[2 * node].min_val, min_seg_tree[2 * node + 1].min_val);
    }
}

// Update range [l, r] by adding delta
void update_min_tree(int node, int start, int end, int l, int r, ll delta) {
    // Check for invalid range or range outside node's responsibility
    if (r < start || end < l || l > r) { 
        return;
    }
    // If node's range is fully contained within update range
    if (l <= start && end <= r) {
        min_seg_tree[node].min_val += delta;
        min_seg_tree[node].lazy += delta;
    } else {
        // Push lazy updates before recursing
        push(node, start, end); 
        int mid = start + (end - start) / 2;
        // Recurse down to children
        update_min_tree(2 * node, start, mid, l, r, delta);
        update_min_tree(2 * node + 1, mid + 1, end, l, r, delta);
        // Update internal node value based on children
        min_seg_tree[node].min_val = min(min_seg_tree[2 * node].min_val, min_seg_tree[2 * node + 1].min_val);
    }
}

// Query the minimum value in a range [l, r] in the segment tree for f(r)
ll query_min_tree(int node, int start, int end, int l, int r) {
    // Check for invalid range or range outside node's responsibility
    if (r < start || end < l || l > r) { 
        return LL_INF; // Return identity element for min
    }
    // If node's range is fully contained within query range
    if (l <= start && end <= r) {
        return min_seg_tree[node].min_val;
    }
    // Push lazy updates before recursing
    push(node, start, end); 
    int mid = start + (end - start) / 2;
    // Recurse down to children
    ll p1 = query_min_tree(2 * node, start, mid, l, r);
    ll p2 = query_min_tree(2 * node + 1, mid + 1, end, l, r);
    // Combine results from children
    return min(p1, p2);
}


int main() {
    // Faster I/O
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    int N;
    cin >> N;

    vector<ll> A(N); // Store the initial array A
    for (int i = 0; i < N; ++i) {
        cin >> A[i];
    }

    // Handle the N=1 case separately as the main logic relies on K = N-1 > 0.
    if (N == 1) {
        int Q;
        cin >> Q;
        while (Q--) {
            int i; // Query index (1-based)
            ll x; // New value
            cin >> i >> x;
            A[i - 1] = x; // Update A
            // For N=1, the minimum operations needed is max(0, A[0] - (N-2)) = max(0, A[0] - (-1)) = max(0, A[0] + 1)
            cout << max(0LL, A[0] + 1) << "\n";
        }
        return 0;
    }

    // K = N-1 is used frequently in calculations
    ll K = N - 1;
    // N-2 is the target upper bound for A_i values
    ll N_minus_2 = N - 2;

    // Initialize segment tree for T_max calculation
    A_for_Tmax.resize(N);
     for(int i=0; i<N; ++i) {
        // Store A_i - (N-2) for efficient T_max query later
        A_for_Tmax[i] = A[i] - N_minus_2;
     }
    // Allocate memory for the segment tree (4*N is safe)
    max_seg_tree.resize(4 * N); 
    // Build the tree based on initial values
    build_max_tree(1, 0, N - 1);

    // Initialize structures for M' calculation
    ll current_sum_p = 0; // Stores sum of p_i = floor(A_i / K)
    vector<ll> cnt(K, 0); // Stores counts of remainders b_i = A_i % K
    vector<ll> p_vals(N); // Stores p_i for each A_i
    vector<ll> b_vals(N); // Stores b_i for each A_i

    // Calculate initial p_i, b_i, sum_p, and counts
    for (int i = 0; i < N; ++i) {
        // Since A[i] >= 0, standard C++ division and modulo work as floor division/modulo
        p_vals[i] = A[i] / K;
        b_vals[i] = A[i] % K;
        current_sum_p += p_vals[i];
        cnt[b_vals[i]]++;
    }

    // Calculate initial values of f(r) = (K+1)r - K S_r
    initial_f_values.resize(K);
    // S array stores prefix sums of cnt: S[r] = sum_{j=0}^{r-1} cnt[j]
    vector<ll> S(K + 1, 0); 
    for (int r = 0; r < K; ++r) {
        S[r+1] = S[r] + cnt[r];
    }
    
    for (int r = 0; r < K; ++r) {
        // Calculate f(r) using the prefix sum S[r]
        initial_f_values[r] = (K + 1) * (ll)r - K * S[r];
    }

    // Build segment tree for f(r) values
    min_seg_tree.resize(4 * K); 
    // Only build if K > 0 (i.e., N >= 2)
    if (K > 0) { 
         build_min_tree(1, 0, K - 1);
    }

    // Process Queries
    int Q;
    cin >> Q;
    while (Q--) {
        int i_idx; // Query index (1-based)
        ll x; // New value for A[i_idx-1]
        cin >> i_idx >> x;
        i_idx--; // Adjust to 0-based index

        // Update T_max segment tree with the new value x - (N-2)
        update_max_tree(1, 0, N - 1, i_idx, x - N_minus_2);
        // Query the overall maximum value from the T_max tree
        ll current_max_A_minus_N2 = query_max_tree(1, 0, N - 1, 0, N - 1);
        // T_max is max(0, overall maximum)
        ll T_max = max(0LL, current_max_A_minus_N2);

        // Update M' related structures based on the change in A[i_idx]
        ll old_p = p_vals[i_idx]; // Old p value
        ll old_b = b_vals[i_idx]; // Old remainder value
        
        // Remove effect of old value
        current_sum_p -= old_p;
        cnt[old_b]--;
        
        // Update the f(r) segment tree due to change in cnt[old_b]
        if (K > 0) { 
             // Decrementing cnt[old_b] increases f(r) by K for all r > old_b
             // Apply range update [old_b + 1, K - 1] with delta = K
             if (old_b + 1 <= K - 1) { // Check if range is valid
                update_min_tree(1, 0, K - 1, old_b + 1, K - 1, K);
            }
        }

        // Calculate new p and b values for x
        ll new_p = x / K;
        ll new_b = x % K;
        
        // Store new values
        p_vals[i_idx] = new_p;
        b_vals[i_idx] = new_b;
        
        // Add effect of new value
        current_sum_p += new_p;
        cnt[new_b]++;
        
        // Update the f(r) segment tree due to change in cnt[new_b]
        if (K > 0) {
            // Incrementing cnt[new_b] decreases f(r) by K for all r > new_b
            // Apply range update [new_b + 1, K - 1] with delta = -K
            if (new_b + 1 <= K - 1) { // Check if range is valid
                update_min_tree(1, 0, K - 1, new_b + 1, K - 1, -K);
            }
        }
        
        // Query the minimum f(r) value from the updated segment tree
        ll min_f_r = 0; // Default for K=0 (N=1 case)
        if (K > 0) { // If K>=1 (N>=2)
            min_f_r = query_min_tree(1, 0, K - 1, 0, K - 1);
        } 

        // Calculate M' using the current sum_p and min_f_r
        // M' = min_r M(r) = min_r (K * sum_p + f(r)) = K * sum_p + min_r f(r)
        ll M_prime = K * current_sum_p + min_f_r;

        // The final answer is the maximum of T_max and M'
        cout << max(T_max, M_prime) << "\n";
    }

    return 0;
}
0