Skip to content

Commit e0f80dd

Browse files
Add Tutorial for LOJ 1089 - Points in Segments (II) (en) (#450)
1 parent 9055a99 commit e0f80dd

File tree

1 file changed

+113
-0
lines changed

1 file changed

+113
-0
lines changed

1089/en.md

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
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

Comments
 (0)