|
| 1 | +# LOJ 1089 - Points in Segments (II) |
| 2 | + |
| 3 | +## Summary |
| 4 | +The problem involves a set of one-dimensional segments and a set of points. The objective is to count, for each point, how many segments include that point within their range. |
| 5 | + |
| 6 | +Note: **AA** is a valid segment. |
| 7 | + |
| 8 | +## Solution |
| 9 | +First let's simplify the problem a bit. Suppose there is no such segment like: **AA** |
| 10 | + |
| 11 | +Let's think of each segment **AB** as of two points where **A** is the opening of the segment and **B** the ending of it. |
| 12 | + |
| 13 | +Consider the set of all opening and ending points of the segments sorted in increasing order. Iterating over the set, there may be two scenarios: |
| 14 | + |
| 15 | +1. An opening point `A` of segment `AB` is found. `AB` has started. Any point that comes after `A` (or equal to `A`) until we reach the endpoint `B` will be on that segment. |
| 16 | + |
| 17 | +2. An ending point `B` of segment `AB` is found. Ongoing segment `AB` is closed. We can't take any point after that into account. |
| 18 | + |
| 19 | +We can sort our queries so that we can calculate answers for them in increasing order as we iterate over the set **S** while only maintaining a single counter. |
| 20 | + |
| 21 | +That was the general approach. Now, solving the original problems is all about handling the exception case where we may have the same point for many openings and endings. See the code and comments for understading how to handle duplicate points. |
| 22 | + |
| 23 | +## Complexity |
| 24 | +- Time Complexity: O(T * (N * lg(N) + Q * lg(Q)). |
| 25 | +- Memory Complexity: O(N + Q). |
| 26 | + |
| 27 | +## Code |
| 28 | + |
| 29 | +### C++ |
| 30 | + |
| 31 | +```cpp |
| 32 | +#include <bits/stdc++.h> |
| 33 | + |
| 34 | +using namespace std; |
| 35 | + |
| 36 | +typedef pair <int, int> pii; |
| 37 | + |
| 38 | + |
| 39 | +int main() { |
| 40 | + |
| 41 | + // for fast I/O |
| 42 | + ios_base::sync_with_stdio(false); |
| 43 | + cin.tie(nullptr); |
| 44 | + |
| 45 | + int t; |
| 46 | + cin >> t; |
| 47 | + |
| 48 | + for(int ts = 1; ts <= t; ++ts) { |
| 49 | + int n, q; |
| 50 | + cin >> n >> q; |
| 51 | + |
| 52 | + vector <pii> point, query; |
| 53 | + vector <int> ans(q); |
| 54 | + for(int i = 0; i < n; ++i) { |
| 55 | + int a, b; |
| 56 | + cin >> a >> b; |
| 57 | + |
| 58 | + // 0 -> opening and 1 -> ending |
| 59 | + point.push_back({a, 0}); |
| 60 | + point.push_back({b, 1}); |
| 61 | + } |
| 62 | + sort(point.begin(), point.end()); |
| 63 | + |
| 64 | + for(int i = 0; i < q; ++i) { |
| 65 | + int p; |
| 66 | + cin >> p; |
| 67 | + |
| 68 | + // saving each query with their corresponding index |
| 69 | + query.push_back({p, i}); |
| 70 | + } |
| 71 | + sort(query.begin(), query.end()); |
| 72 | + |
| 73 | + int cnt = 0, idx = 0, accumulator = 0, ending = 0; |
| 74 | + for(int i = 0; i < (int)point.size(); ++i) { |
| 75 | + if (point[i].second == 0) { |
| 76 | + accumulator++; |
| 77 | + } |
| 78 | + else { |
| 79 | + ending++; // segments that have been closed for the later points |
| 80 | + } |
| 81 | + if (i < (int)point.size() && point[i+1].first == point[i].first) { // accumulating cases with same opening or ending: (p, 0) or (p, 1) |
| 82 | + continue; |
| 83 | + } |
| 84 | + |
| 85 | + // case 1: query points strictly less than current point in consideration |
| 86 | + while (idx < q && query[idx].first < point[i].first) { |
| 87 | + ans[query[idx++].second] = cnt; |
| 88 | + } |
| 89 | + // case 2: query points equal to current point in consideration |
| 90 | + while (idx < q && query[idx].first == point[i].first) { |
| 91 | + ans[query[idx++].second] = cnt + accumulator; |
| 92 | + } |
| 93 | + cnt += accumulator-ending; |
| 94 | + accumulator = ending = 0; |
| 95 | + } |
| 96 | + |
| 97 | + // corner case: coming out of loop before the last point being considered |
| 98 | + while (idx < q && query[idx].first < point.back().first) { |
| 99 | + ans[query[idx++].second] = cnt; |
| 100 | + } |
| 101 | + while (idx < q && query[idx].first == point.back().first) { |
| 102 | + ans[query[idx++].second] = cnt + accumulator; |
| 103 | + } |
| 104 | + |
| 105 | + cout << "Case " << ts << ":\n"; |
| 106 | + for(int i = 0; i < q; ++i) { |
| 107 | + cout << ans[i] << '\n'; |
| 108 | + } |
| 109 | + } |
| 110 | + |
| 111 | + return 0; |
| 112 | +} |
| 113 | +``` |
0 commit comments