結果
問題 |
No.1982 [Cherry 4th Tune B] 絶険
|
ユーザー |
![]() |
提出日時 | 2025-05-14 13:03:45 |
言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
結果 |
MLE
|
実行時間 | - |
コード長 | 11,627 bytes |
コンパイル時間 | 1,110 ms |
コンパイル使用メモリ | 75,704 KB |
実行使用メモリ | 815,396 KB |
最終ジャッジ日時 | 2025-05-14 13:05:48 |
合計ジャッジ時間 | 23,425 ms |
ジャッジサーバーID (参考情報) |
judge1 / judge4 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
other | AC * 23 MLE * 7 -- * 5 |
コンパイルメッセージ
main.cpp: In function ‘int main()’: main.cpp:164:10: warning: ignoring return value of ‘int scanf(const char*, ...)’ declared with attribute ‘warn_unused_result’ [-Wunused-result] 164 | scanf("%d %d %d", &N_input, &K_input, &Q_input); | ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ main.cpp:168:14: warning: ignoring return value of ‘int scanf(const char*, ...)’ declared with attribute ‘warn_unused_result’ [-Wunused-result] 168 | scanf("%d %d %d %lld", &L_ops[k], &R_ops[k], &C_ops[k], &H_ops[k]); | ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ main.cpp:172:14: warning: ignoring return value of ‘int scanf(const char*, ...)’ declared with attribute ‘warn_unused_result’ [-Wunused-result] 172 | scanf("%d %lld", &IQ_queries[q], &XQ_queries[q]); | ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ソースコード
#include <iostream> #include <vector> #include <numeric> #include <cstdio> // Use C-style IO for potentially faster execution using namespace std; // Define type for long long integers typedef long long ll; // Constants based on problem constraints const int MAXN_Q = 200005; // Maximum N (number of sections) and Q (number of queries) const int MAXK = 200005; // Maximum K (number of operations) // Input variables declaration int N_input, K_input, Q_input; // Number of sections, operations, queries int L_ops[MAXK], R_ops[MAXK], C_ops[MAXK]; // Parameters for K operations: Left section, Right section, Color ll H_ops[MAXK]; // Height for K operations int IQ_queries[MAXN_Q]; // Section index for Q queries ll XQ_queries[MAXN_Q]; // Target height X_q for Q queries // Node structure for the Persistent Segment Tree struct Node { ll sum = 0; // Sum of heights in the node's range ll lazy = 0; // Lazy tag for pending updates int left = 0; // Index of the left child node in the `nodes` pool (0 means null) int right = 0; // Index of the right child node in the `nodes` pool (0 means null) }; vector<Node> nodes; // Node pool implemented as a vector int node_idx = 0; // Counter for allocated nodes, points to the next available index in the `nodes` pool // Function to create a new node in the pool // It copies the state from a `template_node_idx` (default is 0, the dummy node) // Returns the index of the newly created node int newNode(int template_node_idx = 0) { // vector `push_back` automatically handles resizing if needed nodes.push_back(nodes[template_node_idx]); // Increment node counter and return the index of the newly added node return ++node_idx; } // Function to propagate lazy tags downwards from `node_p` covering range [l, r] // This is essential for lazy propagation in segment trees void push(int node_p, int l, int r) { // If the node has no pending lazy update or it's a leaf node, return if (nodes[node_p].lazy == 0 || l == r) { return; } ll lazy_val = nodes[node_p].lazy; // Get the lazy value to propagate int m = l + (r - l) / 2; // Calculate midpoint for splitting range // Get the indices of the current children (these act as templates for new children) int current_left = nodes[node_p].left; int current_right = nodes[node_p].right; // Create a new left child node by copying the template state nodes[node_p].left = newNode(current_left); // Apply the lazy value to the new left child's sum // Use (ll) cast to ensure multiplication is done using long long nodes[nodes[node_p].left].sum += lazy_val * (ll)(m - l + 1); // Add the lazy value to the new left child's lazy tag for further propagation nodes[nodes[node_p].left].lazy += lazy_val; // Create a new right child node similarly nodes[node_p].right = newNode(current_right); // Apply lazy value to the new right child's sum nodes[nodes[node_p].right].sum += lazy_val * (ll)(r - (m + 1) + 1); // Add lazy value to the new right child's lazy tag nodes[nodes[node_p].right].lazy += lazy_val; // Clear the lazy tag of the current node since it has been propagated nodes[node_p].lazy = 0; } // Function to perform a range update on the segment tree // Adds 'value' to all elements in the range [target_L, target_R] // Based on persistent node `node_p` covering range [l, r] // Creates new nodes along the path (persistence) // Returns the index of the new root node of the updated subtree int update(int node_p, int l, int r, int target_L, int target_R, ll value) { // Create a new node for the current position on the path, copying state from `node_p` int new_node_p = newNode(node_p); // Case 1: The current node's range [l, r] is fully contained within the target range [target_L, target_R] if (target_L <= l && r <= target_R) { // Apply the update directly to this node's sum and lazy tag nodes[new_node_p].sum += value * (ll)(r - l + 1); // Use (ll) cast for safety nodes[new_node_p].lazy += value; // Return the index of this updated node return new_node_p; } // Case 2: Partial overlap or no overlap. Need to recurse. // First, push down any pending lazy updates from the *new* node before recursing. push(new_node_p, l, r); int m = l + (r - l) / 2; // Midpoint for splitting range // If the target range overlaps with the left child's range [l, m] if (target_L <= m) { // Recursively update the left child. The returned index is the new left child. nodes[new_node_p].left = update(nodes[new_node_p].left, l, m, target_L, target_R, value); } // If the target range overlaps with the right child's range [m+1, r] if (target_R > m) { // Recursively update the right child. The returned index is the new right child. nodes[new_node_p].right = update(nodes[new_node_p].right, m + 1, r, target_L, target_R, value); } // After potential updates to children, recalculate the sum for the current node // The sum is based on the sums of its potentially updated children. nodes[new_node_p].sum = nodes[nodes[new_node_p].left].sum + nodes[nodes[new_node_p].right].sum; // Return the index of this updated node return new_node_p; } // Function to query the value (total height) at a specific point `target_idx` // Uses the segment tree rooted at `node_p` covering range [l, r] ll query_simple(int node_p, int l, int r, int target_idx) { // Base case: Reached the leaf node corresponding to `target_idx` if (l == r) { // The sum at the leaf node already incorporates all propagated lazy updates return nodes[node_p].sum; } // Before recursing, push down any pending lazy updates from the current node push(node_p, l, r); int m = l + (r - l) / 2; // Midpoint // Decide which child path to follow based on `target_idx` if (target_idx <= m) { // Query the left child return query_simple(nodes[node_p].left, l, m, target_idx); } else { // Query the right child return query_simple(nodes[node_p].right, m + 1, r, target_idx); } } // Stores the root indices for each version of the persistent segment tree (k=0 to K) vector<int> roots; // Function to build the initial segment tree structure (representing state with all heights 0) // Recursively builds the tree for range [l, r] // Returns the index of the root node of the built subtree. int build(int l, int r) { // Create a node with default values (sum=0, lazy=0, children=0) int node_p = newNode(); // Base case: If it's a leaf node if (l == r) { return node_p; } // Recursive step: Build left and right children int m = l + (r - l) / 2; nodes[node_p].left = build(l, m); nodes[node_p].right = build(m + 1, r); // Initial sum is 0, no need to combine children sums yet. return node_p; } int main() { // Read N, K, Q using scanf scanf("%d %d %d", &N_input, &K_input, &Q_input); // Read K operations' parameters for (int k = 1; k <= K_input; ++k) { scanf("%d %d %d %lld", &L_ops[k], &R_ops[k], &C_ops[k], &H_ops[k]); } // Read Q queries' parameters for (int q = 1; q <= Q_input; ++q) { scanf("%d %lld", &IQ_queries[q], &XQ_queries[q]); } // Pre-allocate memory for the node pool to avoid reallocations during updates // Estimate max nodes needed: O(N + K log N). With N, K = 2e5, logN ~ 18. Roughly 8 million nodes needed. nodes.reserve(8000000); // Add a dummy node at index 0. Node indices used will be >= 1. nodes.emplace_back(); node_idx = 0; // Reset node counter after adding dummy node // Resize the `roots` vector to hold K+1 root indices roots.resize(K_input + 1); // Build the initial tree (version 0) representing the state before any operations roots[0] = build(1, N_input); // Build the persistent segment tree versions by applying operations k=1 to K for (int k = 1; k <= K_input; ++k) { // Constraint H_k >= 1 ensures H_ops[k] > 0. Update only if H_k > 0. // Create version k based on version k-1 by applying the k-th operation's update roots[k] = update(roots[k-1], 1, N_input, L_ops[k], R_ops[k], H_ops[k]); } // Process the Q queries for (int q = 1; q <= Q_input; ++q) { int iq = IQ_queries[q]; // Section index for the current query ll xq = XQ_queries[q]; // Target height X_q for the current query // We are interested in height X_q - 0.5. // Compare cumulative heights with this value. To avoid floats, we use integer arithmetic: // Compare 2 * CumulativeHeight with 2 * (X_q - 0.5) = 2*X_q - 1. ll target_Y = 2 * xq - 1; // Check edge case where target height is below ground level (X_q < 1 implies target_Y < 1). // Problem constraints state X_q >= 1, so target_Y >= 1. This check is defensive. if (target_Y <= 0) { printf("-1\n"); continue; } // Query the total height at section `iq` after all K operations (using tree version K) ll total_height = query_simple(roots[K_input], 1, N_input, iq); // Check if the target height (X_q - 0.5) is above the final total wall height // Equivalent to checking if 2 * total_height < target_Y if (2 * total_height < target_Y) { // Target height is unreachable printf("-1\n"); continue; } // Binary search over operation indices [1, K] to find the *minimal* k* such that // the cumulative height at section `iq` after operation k* is >= X_q - 0.5. // This is equivalent to finding minimal k* such that 2 * Height(iq, k*) >= target_Y. int low = 1, high = K_input; int ans_k = 0; // Initialize answer k* to 0 (indicates not found yet) while (low <= high) { int mid = low + (high - low) / 2; // Calculate midpoint safely // Query cumulative height at section `iq` after `mid` operations (using tree version `mid`) ll current_height_sum = query_simple(roots[mid], 1, N_input, iq); // Check if the height threshold is met or exceeded if (2 * current_height_sum >= target_Y) { // Found a potential candidate operation index `mid`. Store it. ans_k = mid; // Try to find an even earlier operation (smaller index) by searching in the left half [low, mid-1] high = mid - 1; } else { // Height threshold not met. Need operations with larger indices. Search in the right half [mid+1, high] low = mid + 1; } } // After binary search, `ans_k` holds the index of the operation that first pushed the height >= X_q - 0.5. // If the initial total_height check passed, ans_k should be found and > 0. if (ans_k > 0) { // Print the color associated with operation `ans_k` printf("%d\n", C_ops[ans_k]); } else { // This case theoretically shouldn't happen if the total height check passed and total height > 0. // If total height is 0, the initial check handles it. // Print -1 as a fallback for unexpected scenarios. printf("-1\n"); } } return 0; }