結果
問題 |
No.1394 Changing Problems
|
ユーザー |
![]() |
提出日時 | 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 |
ソースコード
#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; }