結果
| 問題 |
No.255 Splarrraaay スプラーレェーーイ
|
| コンテスト | |
| ユーザー |
qwewe
|
| 提出日時 | 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.
}
qwewe