結果
問題 |
No.255 Splarrraaay スプラーレェーーイ
|
ユーザー |
![]() |
提出日時 | 2025-05-14 12:58:33 |
言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
結果 |
WA
|
実行時間 | - |
コード長 | 14,899 bytes |
コンパイル時間 | 1,232 ms |
コンパイル使用メモリ | 100,824 KB |
実行使用メモリ | 128,172 KB |
最終ジャッジ日時 | 2025-05-14 13:00:03 |
合計ジャッジ時間 | 15,238 ms |
ジャッジサーバーID (参考情報) |
judge2 / judge1 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
other | AC * 1 WA * 9 |
ソースコード
#include <iostream> #include <vector> #include <map> #include <set> #include <algorithm> #include <tuple> // Required for std::tuple using namespace std; // Use unsigned long long for sums to handle potentially large values and ensure correct modulo arithmetic. typedef unsigned long long ull; // Define the modulus constant. The ULL suffix ensures it's treated as unsigned long long. const ull MOD = 1000000000000000009ULL; // Structure representing a node in the segment tree struct Node { // Stores the sum of thicknesses for each of the 5 teams (indexed 0-4) within the node's range. ull SumThickness[5]; // Lazy propagation tag: 0 indicates no pending update, 1-5 indicates the ID of the team whose paint action is pending. int lazy_team; // The range of elementary interval indices [Lidx, Ridx] covered by this node. int Lidx, Ridx; // The actual coordinate range [P_left, P_right-1] covered by this node. P_right is the coordinate after the last index covered. long long P_left, P_right; }; vector<Node> tree; // Vector to store the segment tree nodes. Using 1-based indexing for nodes. vector<long long> P; // Vector to store the sorted unique coordinates that define the elementary intervals. map<long long, int> coord_to_idx; // Map to quickly find the index in P corresponding to a coordinate value. /** * @brief Applies a lazy tag update to a segment tree node. * Represents the effect of team X painting the entire range covered by this node. * Updates SumThickness based on the derived logic and sets the lazy tag. * @param target_idx The index of the node in the tree vector to apply the update to. * @param X The ID of the team (1-5) performing the paint action. */ void apply_lazy(int target_idx, int X) { // If X is 0, it's not a valid team ID for painting, possibly indicates no update needed. if (X == 0) return; // Calculate the length of the coordinate range covered by this node. long long node_len = tree[target_idx].P_right - tree[target_idx].P_left; // Ensure length is not negative (shouldn't happen with correct build, but safety check). if (node_len < 0) node_len = 0; // Calculate the length modulo MOD. Use careful modulo arithmetic for potentially negative intermediate results (though node_len shouldn't be negative). ull L_mod = (node_len % (long long)MOD + (long long)MOD) % MOD; // Apply the update logic: // SumThickness for team X increases by the range length (mod MOD). // SumThickness for all other teams is reset to 0. // Use X-1 for 0-based array indexing. tree[target_idx].SumThickness[X - 1] = (tree[target_idx].SumThickness[X - 1] + L_mod) % MOD; for (int Y = 1; Y <= 5; ++Y) { if (Y != X) { tree[target_idx].SumThickness[Y - 1] = 0; } } // Set the lazy tag on this node to indicate that an update from team X is pending propagation. tree[target_idx].lazy_team = X; } /** * @brief Pushes the lazy tag from a parent node down to its children. * Ensures children nodes are updated before they are accessed or further recursion. * @param idx The index of the parent node in the tree vector. */ void push(int idx) { // If there's no lazy tag or if it's a leaf node (no children to push to), do nothing. if (tree[idx].lazy_team == 0 || tree[idx].Lidx == tree[idx].Ridx) { // On a leaf node, any lazy tag is considered 'applied' as there are no children. Clear the tag. if (tree[idx].Lidx == tree[idx].Ridx) tree[idx].lazy_team = 0; return; } int lazy_X = tree[idx].lazy_team; // The team ID from the lazy tag. // Apply the lazy update to the left child (index 2*idx). apply_lazy(2 * idx, lazy_X); // Apply the lazy update to the right child (index 2*idx+1). apply_lazy(2 * idx + 1, lazy_X); // After pushing the tag down, clear the lazy tag on the current node. tree[idx].lazy_team = 0; } /** * @brief Combines the results (SumThickness) from children nodes into their parent node. * Called after recursive calls in update/query to maintain correct aggregate values in parent nodes. * @param idx The index of the parent node in the tree vector. */ void combine(int idx) { // The parent's SumThickness for each team is the sum of its children's SumThickness, modulo MOD. for (int i = 0; i < 5; ++i) { tree[idx].SumThickness[i] = (tree[2 * idx].SumThickness[i] + tree[2 * idx + 1].SumThickness[i]) % MOD; } } /** * @brief Builds the segment tree recursively. * Initializes nodes with their ranges and default values (0 thickness, no lazy tag). * @param idx The current node index in the tree vector (1-based). * @param L_idx The starting index of the elementary interval range covered by this node. * @param R_idx The ending index of the elementary interval range covered by this node. */ void build(int idx, int L_idx, int R_idx) { // Set node properties based on the interval range it covers. tree[idx].Lidx = L_idx; tree[idx].Ridx = R_idx; tree[idx].P_left = P[L_idx]; // The starting coordinate of the range. tree[idx].P_right = P[R_idx + 1]; // The coordinate marking the end of the range (+1). P has m+1 elements. tree[idx].lazy_team = 0; // Initialize with no lazy tag. // Initialize thickness sums for all teams to 0. for (int i = 0; i < 5; ++i) { tree[idx].SumThickness[i] = 0; } // Base case: If it's a leaf node (covers a single elementary interval), return. if (L_idx == R_idx) { return; } // Recursive step: Build left and right children. int M_idx = L_idx + (R_idx - L_idx) / 2; // Calculate midpoint index. build(2 * idx, L_idx, M_idx); // Build left child. build(2 * idx + 1, M_idx + 1, R_idx); // Build right child. // No need to call combine initially, as all sums start at 0. } /** * @brief Updates the segment tree for a given range of elementary intervals due to a paint action by team_X. * Uses lazy propagation for efficiency. * @param idx The current node index in the tree vector. * @param query_L_idx The starting index of the query range (elementary intervals). * @param query_R_idx The ending index of the query range. * @param team_X The ID of the team (1-5) performing the paint action. */ void update(int idx, int query_L_idx, int query_R_idx, int team_X) { int L_idx = tree[idx].Lidx; // Node's starting interval index. int R_idx = tree[idx].Ridx; // Node's ending interval index. // If the query range is completely outside the node's range, do nothing. if (query_R_idx < L_idx || R_idx < query_L_idx) { return; } // If the node's range is fully contained within the query range: if (query_L_idx <= L_idx && R_idx <= query_R_idx) { // Apply the lazy update to this node. This handles the update for the entire range covered by this node. apply_lazy(idx, team_X); return; // Stop recursion down this path. } // If the node's range partially overlaps the query range: // First, push any existing lazy tag down to children. This ensures their state is current before further updates. push(idx); // Recursively call update on children. M_idx calculation is implicit in child indexing. update(2 * idx, query_L_idx, query_R_idx, team_X); // Update left child. update(2 * idx + 1, query_L_idx, query_R_idx, team_X); // Update right child. // After children are updated, update the current node's state by combining their results. combine(idx); } /** * @brief Queries the segment tree for the sum of thicknesses for all teams within a given range of elementary intervals. * @param idx The current node index in the tree vector. * @param query_L_idx The starting index of the query range (elementary intervals). * @param query_R_idx The ending index of the query range. * @return A vector<ull> containing the sum of thicknesses for each of the 5 teams in the queried range. */ vector<ull> query(int idx, int query_L_idx, int query_R_idx) { int L_idx = tree[idx].Lidx; // Node's starting interval index. int R_idx = tree[idx].Ridx; // Node's ending interval index. vector<ull> result(5, 0); // Initialize result vector with 0s for all 5 teams. // If the query range is completely outside the node's range, return all zeros. if (query_R_idx < L_idx || R_idx < query_L_idx) { return result; } // If the node's range is fully contained within the query range: if (query_L_idx <= L_idx && R_idx <= query_R_idx) { // Return the sums stored in this node. for(int i=0; i<5; ++i) result[i] = tree[idx].SumThickness[i]; return result; } // If the node's range partially overlaps the query range: // Push any existing lazy tag down to ensure children's states are accurate before querying them. push(idx); // Recursively query children and combine their results. vector<ull> left_sums = query(2 * idx, query_L_idx, query_R_idx); // Query left child. vector<ull> right_sums = query(2 * idx + 1, query_L_idx, query_R_idx); // Query right child. // Combine the sums from children, applying modulo arithmetic. for (int i = 0; i < 5; ++i) { result[i] = (left_sums[i] + right_sums[i]) % MOD; } return result; // Return the combined sums. } int main() { // Faster I/O operations ios_base::sync_with_stdio(false); cin.tie(NULL); long long N; // Length of the array. Can be very large. int Q; // Number of events (paint actions or bonus chances). cin >> N >> Q; // Use a set to collect unique coordinates. It automatically handles duplicates and sorting. set<long long> coords; coords.insert(0); // Always include the start coordinate 0. coords.insert(N); // Always include coordinate N (represents the point after the last index N-1). // Store events details (type, range) to process after coordinate compression and tree building. vector<tuple<int, long long, long long>> events(Q); for (int k = 0; k < Q; ++k) { int x; // Event type: 0 for bonus, 1-5 for team paint. long long l, r; // Range [l, r] for the event. cin >> x >> l >> r; events[k] = make_tuple(x, l, r); // Add relevant coordinates l and r+1 to the set. These define the boundaries of elementary intervals. // Check bounds to ensure coordinates are within [0, N]. if (l >= 0 && l <= N) coords.insert(l); if (r + 1 >= 0 && r + 1 <= N) coords.insert(r + 1); } // Populate vector P with sorted unique coordinates from the set. for(long long c : coords) { P.push_back(c); } // Create a map from coordinate value to its index in P for quick lookups. for (int i = 0; i < P.size(); ++i) { coord_to_idx[P[i]] = i; } // Calculate the number of elementary intervals (m = number of unique coordinates - 1). int m = P.size() - 1; // Handle edge case: If N=0 or no operations result in intervals (m <= 0). if (m <= 0) { cout << "0 0 0 0 0" << endl; // Print all zeros and exit. return 0; } // Allocate memory for the segment tree. Size 4*m is a safe upper bound for a binary tree based on m leaves. Add a small buffer for safety. tree.resize(4 * m + 4); // Build the segment tree structure over the elementary interval indices [0, m-1]. build(1, 0, m - 1); // Use 1-based indexing for segment tree nodes. // Initialize bonus points for each team to 0. vector<ull> BonusPoints(5, 0); // Process each event chronologically. for (int k = 0; k < Q; ++k) { int x = get<0>(events[k]); // Event type. long long l = get<1>(events[k]); // Left endpoint of range. long long r = get<2>(events[k]); // Right endpoint of range. // Ensure the range [l, r] is valid within the array bounds [0, N-1]. // Clamp coordinates defensively, though input constraints should guarantee validity (0 <= l <= r < N). l = max(0LL, l); r = min(N - 1, r); // If after clamping l > r, the interval is empty, skip. if (l > r) continue; // Map the coordinate range [l, r] to the corresponding range of elementary interval indices [l_idx, r_idx]. int l_idx = coord_to_idx[l]; // Find index for coordinate l. // Find index for coordinate r+1. Map lookup is safe because we added r+1 to coords set earlier. int r_idx_plus_1 = coord_to_idx[r + 1]; int r_idx = r_idx_plus_1 - 1; // The index of the last elementary interval involved in the range [l, r]. // If the calculated index range is invalid (e.g., l_idx > r_idx), skip this event. if (l_idx > r_idx) continue; if (x == 0) { // Bonus chance event // Query the segment tree for sums of thicknesses in the specified range [l_idx, r_idx]. vector<ull> sums = query(1, l_idx, r_idx); ull max_sum = 0; // Find the maximum sum among all teams. for (int i = 0; i < 5; ++i) { if (sums[i] > max_sum) { max_sum = sums[i]; } } // If the maximum sum is 0, no bonus points awarded. if (max_sum == 0) continue; int max_count = 0; // Count teams achieving the maximum sum. int winner_team_idx = -1; // Store index (0-4) of potential winning team. for (int i = 0; i < 5; ++i) { if (sums[i] == max_sum) { max_count++; winner_team_idx = i; } } // If exactly one team achieved the maximum sum, award bonus points (max_sum) to that team. if (max_count == 1) { BonusPoints[winner_team_idx] = (BonusPoints[winner_team_idx] + max_sum) % MOD; } } else { // Painting action event by team x (where x is 1-5). // Update the segment tree for the specified range [l_idx, r_idx] and team x. update(1, l_idx, r_idx, x); } } // After processing all events, query the total thickness sums for the entire array range [0, N-1]. // This corresponds to querying the full range of elementary intervals [0, m-1]. vector<ull> final_thickness_sums = query(1, 0, m - 1); // Calculate and print the final score for each team (A, B, C, D, E). for (int i = 0; i < 5; ++i) { // Final score = (Total Thickness Sum + Total Accumulated Bonus Points) % MOD. ull final_score = (final_thickness_sums[i] + BonusPoints[i]) % MOD; cout << final_score << (i == 4 ? "" : " "); // Print score with space separator, no space after the last score. } cout << endl; // Print newline at the end. return 0; // Indicate successful execution. }