Skip to content

Commit 4eed262

Browse files
committed
Update content/5_Plat/Range_Sweep.mdx
1 parent 4b2ef69 commit 4eed262

File tree

1 file changed

+74
-25
lines changed

1 file changed

+74
-25
lines changed

content/5_Plat/Range_Sweep.mdx

+74-25
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
id: range-sweep
33
title: 'Range Queries with Sweep Line'
4-
author: Benjamin Qi, Andi Qu, Dong Liu
4+
author: Benjamin Qi, Andi Qu, Dong Liu, Peng Bai
55
prerequisites:
66
- PURS
77
- lis
@@ -13,9 +13,6 @@ frequency: 2
1313

1414
<FocusProblem problem="sample2" />
1515

16-
## Tutorial
17-
18-
<IncompleteSection />
1916

2017
## Solution - Intersection Points
2118

@@ -46,10 +43,12 @@ Our answer would be the sum of all the queries.
4643
#include <bits/stdc++.h>
4744
using namespace std;
4845

49-
int bit[2000005];
46+
// max coordinate
47+
const int X = 1e6;
48+
int bit[2 * X + 1];
5049

5150
void update(int i, int x) {
52-
for (; i < 2000005; i += i & (-i)) bit[i] += x;
51+
for (; i <= 2 * X; i += i & (-i)) bit[i] += x;
5352
}
5453
int query(int i) {
5554
int sum = 0;
@@ -62,8 +61,11 @@ vector<array<int, 4>> v;
6261

6362
int main() {
6463
cin.tie(0)->sync_with_stdio(0);
65-
6664
cin >> n;
65+
// types of events (order for if some y values are equal):
66+
// 1 -> start of vertical segment
67+
// 2 -> horizontal segment
68+
// 3 -> end of vertical segment
6769
for (int i = 0, x1, y1, x2, y2; i < n; ++i) {
6870
cin >> x1 >> y1 >> x2 >> y2;
6971
if (y1 == y2) v.push_back({y1, 2, x1, x2});
@@ -75,11 +77,11 @@ int main() {
7577
sort(begin(v), end(v));
7678

7779
long long ans = 0;
78-
for (auto x : v) {
79-
x[2] += 1000001, x[3] += 1000001;
80-
if (x[1] == 1) update(x[2], 1);
81-
else if (x[1] == 2) ans += query(x[3]) - query(x[2] - 1);
82-
else update(x[2], -1);
80+
for (auto [y, type, x1, x2] : v) {
81+
x1 += X, x2 += X;
82+
if (type == 1) update(x1, 1);
83+
else if (type == 2) ans += query(x2) - query(x1 - 1);
84+
else update(x1, -1);
8385
}
8486
cout << ans << '\n';
8587
}
@@ -91,20 +93,50 @@ int main() {
9193

9294
## Solution - Springboards
9395

94-
<IncompleteSection />
96+
**Naive DP:** $\mathcal{O}(P^2)$
9597

96-
The problem boils down to having a data structure that supports the following
97-
operations:
98+
The first step is to create a DP to solve the first subtask. The states are the springboards and the transitions are between springboards. First, sort the springboards by the pair $(x_1, y_1)$ in increasing order. It is possible to show that for all $i$, $j$, where $i < j$, Bessie cannot use springboard $j$ then $i$ later.
9899

99-
1. Add a pair $(a,b)$.
100-
2. For any $x$, query the minimum value of $b$ over all pairs satisfying
101-
$a\le x$.
100+
For each springboard $A_i$, let $ans[i]$ denote the minimum distance needed to walk to the start point of springboard $i$.
101+
102+
Let $dist(a, b)$ be the walking distance from the end of springboard $a$ and the start of springboard $b$.
103+
104+
$dist(a, b) = x_1[b] + y_1[b] - x_2[a] - y_2[a]$
105+
106+
Then, the transitions are:
107+
108+
$ans[i] = \min\limits_{j < i, x_2[j] \le x_1[i], y_2[j] \le y_1[i]}(ans[j] + dist(j, i))$
109+
110+
**Full Solution:** $\mathcal{O}(P \log P)$
111+
112+
Optimizing the DP involves the use of a min point update range query segment tree. Let's first expand $dist(i, j)$ in the transition formula.
113+
114+
$ans[i] = \min\limits_{j < i, x_2[j] \le x_1[i], y_2[j] \le y_1[i]}(ans[j] + x_1[i] + y_1[i] - x_2[j] - y_2[j])$
115+
116+
$ans[i] = x_1[i] + y_1[i] + \min\limits_{j < i, x_2[j] \le x_1[i], y_2[j] \le y_1[i]}(ans[j] - x_2[j] - y_2[j])$
102117

103-
The [other module](/adv/springboards) describes a simpler way of doing this,
104-
though it's probably more straightforward to do coordinate compression and use a
105-
min segtree. The latter approach is shown below.
118+
We notice that everything inside the $\min$ statement only depends on $j$. The segment tree stores $ans[j] - x_2[j] - y_2[j]$ at index $y_2[j]$. We can seperate the start and end of springboards to create two seperate events from them, still sorting by $(x, y)$. When the event is the start of a springboard, update $ans[i]$ through a segment tree query. When the event is the end of a springboard, update the segment tree.
119+
120+
By processing in order, the first two conditions in the $\min$ statement are always satisfied. The third is where the segment tree comes into play, where querying the range $[0, y_1[i]]$ is sufficent to satisfy all constraints.
121+
122+
Due to the large $N$, coordinate compression is required in the code.
106123

107124
```cpp
125+
#include <bits/stdc++.h>
126+
using namespace std;
127+
#define f first
128+
#define s second
129+
#define pb push_back
130+
#define rep(i, a, b) for(int i = a; i < (b); ++i)
131+
#define all(x) begin(x), end(x)
132+
#define sz(x) (int)(x).size()
133+
typedef long long ll;
134+
typedef pair<int, int> pii;
135+
typedef vector<int> vi;
136+
137+
template<class T> bool ckmin(T& a, const T& b) {
138+
return b < a ? a = b, 1 : 0; } // set a = min(a,b)
139+
108140
/**
109141
* Description: 1D point update, range query where \texttt{comb} is
110142
* any associative operation. If $N=2^p$ then \texttt{seg[1]==query(0,N-1)}.
@@ -139,27 +171,31 @@ template <class T> struct Seg { // comb(ID,b) = b
139171
}
140172
};
141173

174+
const int MX = 1e5 + 5;
142175
Seg<int> S;
143176
int N, P;
144177
int ans[MX];
145178
vi distinct_y;
146179

147180
int query_min(int ind) { return S.query(0, ind); }
148181
void ins(int ind, int val) { S.upd(ind, val); }
149-
int y_index(int y) { return lb(all(distinct_y), y) - begin(distinct_y); }
182+
int y_index(int y) { return lower_bound(all(distinct_y), y) - begin(distinct_y); }
150183

151184
int main() {
152-
setIO("boards");
185+
ios_base::sync_with_stdio(0); cin.tie(0);
186+
freopen("boards.in", "r", stdin);
187+
freopen("boards.out", "w", stdout);
153188
cin >> N >> P;
154189
vector<pair<pair<int, int>, pair<int, int>>> ev;
155190
for (int i = 0; i < P; ++i) {
156191
pair<int, int> a, b;
157192
cin >> a.f >> a.s >> b.f >> b.s;
158-
ev.push_back({a, {i, -1}}); // start point
159-
ev.push_back({b, {i, 1}}); // end point
193+
ev.pb({a, {i, -1}}); // start point
194+
ev.pb({b, {i, 1}}); // end point
160195
distinct_y.pb(a.s);
161196
distinct_y.pb(b.s);
162197
}
198+
163199
sort(all(distinct_y));
164200
sort(begin(ev), end(ev));
165201
S.init(2 * P);
@@ -175,6 +211,19 @@ int main() {
175211
}
176212
```
177213
214+
Bonus: Think of this problem as maximizing the distance covered by springboards to simplify the solution.
215+
216+
## Different Approach - Springboards
217+
It turns out there is also a simpler though less straightforward method to solve this problem.
218+
219+
The problem boils down to having a data structure that supports the following
220+
operations:
221+
222+
1. Add a pair $(a,b)$.
223+
2. For any $x$, query the minimum value of $b$ over all pairs satisfying
224+
$a\le x$.
225+
226+
This solution is described in the [official editorial](https://usaco.org/current/data/sol_boards_gold_jan20.html) and the [other module](/adv/springboards).
178227
## Problems
179228
180229
<Problems problems="sweep" />

0 commit comments

Comments
 (0)