結果
問題 |
No.2220 Range Insert & Point Mex
|
ユーザー |
![]() |
提出日時 | 2025-05-14 13:00:27 |
言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
結果 |
AC
|
実行時間 | 104 ms / 2,000 ms |
コード長 | 8,610 bytes |
コンパイル時間 | 1,044 ms |
コンパイル使用メモリ | 86,416 KB |
実行使用メモリ | 13,328 KB |
最終ジャッジ日時 | 2025-05-14 13:02:41 |
合計ジャッジ時間 | 6,341 ms |
ジャッジサーバーID (参考情報) |
judge1 / judge5 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 3 |
other | AC * 36 |
ソースコード
#include <iostream> #include <vector> #include <map> #include <algorithm> using namespace std; // Use long long for coordinates as they can be up to 10^9 typedef long long ll; // Structure to represent events on the coordinate line struct Event { ll coord; // Coordinate of the event int type; // Type of event: 1 for start interval, 2 for end interval, 3 for query int val; // Value a_i for updates, query index for queries // Custom comparison for sorting events // Sort primarily by coordinate, secondarily by type // The type order determines the sequence of operations at the same coordinate: // 1. Start intervals (+1 updates) // 2. End intervals (-1 updates) // 3. Queries // This ensures the state of the segment tree reflects the set contents exactly AT the query coordinate. bool operator<(const Event& other) const { if (coord != other.coord) { return coord < other.coord; } // If coordinates are equal, process events in order: start intervals (1), then end intervals (2), then queries (3). return type < other.type; } }; // Structure for segment tree nodes struct SegTreeNode { int min_count; // Stores the minimum count of elements within the node's value range }; // Global segment tree vector and parameters related to its size and range vector<SegTreeNode> tree; int N_val_max; // The maximum value index we need to track, which is N_ops (number of operations) int seg_tree_leaf_range; // The size of the leaf range [0, seg_tree_leaf_range - 1] covered by the physical tree structure. It's the smallest power of 2 >= N_val_max + 1. // Build the segment tree recursively // Initializes all counts to 0. // node: current node index (1-based) // L, R: current node's value range [L, R] void build(int node, int L, int R) { if (L == R) { // Leaf node represents a single value. Initialize its count to 0. tree[node] = {0}; } else { int mid = L + (R - L) / 2; build(2 * node, L, mid); // Build left child build(2 * node + 1, mid + 1, R); // Build right child // Parent node's min_count is the minimum of its children's min_counts tree[node].min_count = min(tree[2 * node].min_count, tree[2 * node + 1].min_count); } } // Update the count for a target value in the segment tree // Used for incrementing count (+1) when an interval starts, and decrementing (-1) when it ends. // node: current node index // L, R: current node's value range // target_val: the value whose count needs update // delta: change in count (+1 or -1) void update(int node, int L, int R, int target_val, int delta) { // If target value is outside the current node's range, stop recursion. // This check prevents errors if target_val somehow falls outside the valid range [L, R]. if (target_val < L || target_val > R) { return; } if (L == R) { // Leaf node reached, update its count tree[node].min_count += delta; } else { int mid = L + (R - L) / 2; // Recurse down to the correct child based on target_val if (target_val <= mid) { update(2 * node, L, mid, target_val, delta); } else { update(2 * node + 1, mid + 1, R, target_val, delta); } // Update current node's min_count based on children's updated minimum counts tree[node].min_count = min(tree[2 * node].min_count, tree[2 * node + 1].min_count); } } // Query the segment tree for the minimum index with count 0 within the logical range [0, N_val_max] // This index corresponds to the Mex value. // node: current node index // L, R: current node's value range covered by this physical node // Returns the minimum index with count 0. Returns -1 only if no such index exists (which shouldn't happen based on problem logic). int query_min_zero_idx(int node, int L, int R) { // If minimum count in this node's entire range is > 0, then no element in this range has count 0. if (tree[node].min_count > 0) { return -1; // Indicate no zero count found in this subtree } // If leaf node reached and min_count is 0 (guaranteed by the check above) if (L == R) { // This leaf node corresponds to value L, and its count is 0. Return L. return L; } int mid = L + (R - L) / 2; // Check left child first because we want the *minimum* index. int left_res = query_min_zero_idx(2 * node, L, mid); if (left_res != -1) { // Found a zero-count index in the left subtree. This must be the minimum. return left_res; } // If not found in left subtree, check the right subtree. // Since the parent node's min_count is 0 and left child's min_count is > 0, // the minimum zero-count index must be in the right subtree. return query_min_zero_idx(2 * node + 1, mid + 1, R); } int main() { // Faster I/O operations ios_base::sync_with_stdio(false); cin.tie(NULL); int N_ops; // Number of range insert operations cin >> N_ops; vector<Event> events; // Vector to store all coordinate events for (int i = 0; i < N_ops; ++i) { ll l, r; // Interval bounds [l, r] int a; // Value to insert cin >> l >> r >> a; // We only care about values 'a' in the range [0, N_ops]. // The Mex value can be at most N_ops, because a set formed from N operations // can contain at most N distinct values. The set {0, 1, ..., N_ops} has N_ops+1 elements. // Therefore, S_x cannot contain all elements from {0, ..., N_ops}, meaning Mex(S_x) <= N_ops. // Filter out operations with a > N_ops as they don't affect the Mex if it's <= N_ops. // Also ensure a >= 0 as per problem non-negative integer definition. if (a >= 0 && a <= N_ops) { // Create event for interval start at coordinate 'l' events.push_back({l, 1, a}); // Create event for interval end just after coordinate 'r'. Use coordinate 'r+1'. events.push_back({r + 1, 2, a}); } } int Q; // Number of queries cin >> Q; vector<int> results(Q); // Vector to store results for each query for (int i = 0; i < Q; ++i) { ll xk; // Query coordinate cin >> xk; // Create query event at coordinate 'xk'. Store original query index 'i' in 'val'. events.push_back({xk, 3, i}); } // Sort events based on coordinate, then type. This is crucial for the sweep-line approach. sort(events.begin(), events.end()); // Set up segment tree parameters. The tree covers values from 0 to N_ops. N_val_max = N_ops; // Calculate the size required for the segment tree's leaf layer. // It must be a power of 2 large enough to cover indices up to N_val_max. seg_tree_leaf_range = 1; while(seg_tree_leaf_range <= N_val_max) { // Smallest power of 2 >= N_ops+1 seg_tree_leaf_range *= 2; } // The segment tree array needs about 2 times the leaf range size. tree.resize(2 * seg_tree_leaf_range); // Build the segment tree. It covers the physical range [0, seg_tree_leaf_range - 1]. // The logical range we operate on is [0, N_val_max]. build(1, 0, seg_tree_leaf_range - 1); // Process events in sorted order (sweep line) for (const auto& event : events) { // Updates (type 1 and 2) only affect values within the logical range [0, N_val_max] if (event.type == 1) { // Start interval event: increment count for value event.val if (event.val >= 0 && event.val <= N_val_max) update(1, 0, seg_tree_leaf_range - 1, event.val, 1); } else if (event.type == 2) { // End interval event: decrement count for value event.val if (event.val >= 0 && event.val <= N_val_max) update(1, 0, seg_tree_leaf_range - 1, event.val, -1); } else { // Query event (type 3) int query_idx = event.val; // Retrieve original query index // Query the segment tree for the minimum index (value) with count 0. This is the Mex. results[query_idx] = query_min_zero_idx(1, 0, seg_tree_leaf_range - 1); // The query logic guarantees finding the minimum index <= N_val_max if one exists. // Since Mex <= N_ops is guaranteed, this function should correctly find the Mex. } } // Output the computed Mex values for each query for (int i = 0; i < Q; ++i) { cout << results[i] << "\n"; } return 0; }