Recent CP News

# Manya and sticks || State Space Reduction

## Manya is  playing with sticks

Pussycat Mnya placed  sticks on a straight line. The ith stick is located at position xi and has height . There are no two sticks located at the same position. Manya can push sticks to make them fall to the left or the right side. While falling, a stick can touch its neighbors and make them also fall in the same direction (like dominoes).

More formally: if a stick at position x with height h is falling to the left, it will make all the sticks at positions …x inclusive fall to the left. Similarly, if a stick is falling to the right it will make all the sticks at positionsx…(x+h) inclusive fall to the right.

Now Manya is interested in finding the minimal number of sticks she needs to push to make all N sticks fall.

## Input

The first line contains one integer N  the number of sticks.
Each of the next N lines contains two integers xi,hi  position and height of the ith stick.

Output format:
Print the minimal number of sticks Manya needs to push.

Constraints

15 points

10 points

10 points

65 points
Original constraints

## SAMPLE INPUT

5
1 2
3 1
6 2
7 1
9 2


## SAMPLE OUTPUT

2


## Solution With explanation

This problem could be solved with dynamic programming. But first we need to calculate some additional information about the sticks.

Let’s sort them all by positions in ascending order. If we push i−th stick to the left it may cause some neighbouring sticks also fall to the left. Let l be the leftmost such stick. In a similar way let be the rightmost such stick if we push i−th stick to the right.

Let  be the minimal number of pushes needed to make fall all the sticks in positions  inclusive. We need to consider two options and select one with the minimal value:

Make i-th stick fall to the left
In this case we just need to push i−th stick to the left. And it’ll take  pushes in total.

Make i-th stick fall to the right
Let’s consider all such sticks that if we push one to the right it will make  stick also fall to the right. Suppose current such stick is . Then it will take  pushes to make all i sticks fall. So we need to select such stick that this value is minimal.

Let’s consider implementation details.

In the second option when we try to make i−th stick fall to the right we don’t actually need to consider each stick j all the time. Let’s just store all these sticks and keep them sorted by  values. We’re only interested in a stick with the minimal such value. It can be done with Priority Queue and cost ) for each query. Also do not forget to delete from this storage all such sticks  that rightmostLyingPos(j)<i.

To calculate leftmostLyingPos(i) first we need to find such leftmost stick j that . It can be easily done with Binary Search. And then we need to select minimal number among leftmostLyingPos(j)…leftmostLyingPos(i−1). This part can be done with Segment Tree. Both Binary Search and Segment Tree work in  for each query.

In a similar way to calculate  we need to find such rightmost stick  that . And then we need to select maximal number among .

Total time complexity is

1. #pragma comment(linker, "/STACK:500000000")
2. #define _CRT_SECURE_NO_WARNINGS
3. #include <algorithm>
4. #include <assert.h>
5. #include <bitset>
6. #include <functional>
7. #include <iostream>
8. #include <list>
9. #include <map>
10. #include <math.h>
11. #include <set>
12. #include <stack>
13. #include <stdio.h>
14. #include <stdlib.h>
15. #include <string>
16. #include <string.h>
17. #include <time.h>
18. #include <queue>
19. //#include <unordered_map>
20. //#include <unordered_set>
21. #include <utility>
22. #include <vector>
23. using namespace std;
24. 
25. #define y0 y0ChloeGraceMoretz
26. #define y1 y1ChloeGraceMoretz
27. typedef long long ll;
28. const double PI = acos(-1.0);
29. const double EPS = 1e-9;
30. const int INF = (int)2e9;
31. 
32. struct Stick {
33.  int x, h;
34. 
35.  Stick() {}
36. 
37.  Stick(int _x, int _h) {
38.  x = _x;
39.  h = _h;
40.  }
41. 
42.  const bool operator<(Stick other) const {
43.  return x < other.x;
44.  }
45. };
46. 
47. int leftmostLyingPos[4 * (int)5e5 + 9];
48. int rightmostLyingPos[4 * (int)5e5 + 9];
49. 
50. int queryMin(int x, int l, int r, int i, int j) {
51.  if (i > r || l > j) {
52.  return INF;
53.  } else if (l >= i && r <= j) {
54.  return leftmostLyingPos[x];
55.  } else {
56.  return min(queryMin(2 * x + 1, l, (l + r) / 2, i, j),
57.  queryMin(2 * x + 2, (l + r) / 2 + 1, r, i, j));
58.  }
59. }
60. 
61. int queryMax(int x, int l, int r, int i, int j) {
62.  if (i > r || l > j) {
63.  return -INF;
64.  } else if (l >= i && r <= j) {
65.  return rightmostLyingPos[x];
66.  } else {
67.  return max(queryMax(2 * x + 1, l, (l + r) / 2, i, j),
68.  queryMax(2 * x + 2, (l + r) / 2 + 1, r, i, j));
69.  }
70. }
71. 
72. void updateMin(int x, int l, int r, int pos, int y) {
73.  if (l == r) {
74.  leftmostLyingPos[x] = y;
75.  } else {
76.  if (pos <= (l + r) / 2) {
77.  updateMin(2 * x + 1, l, (l + r) / 2, pos, y);
78.  } else {
79.  updateMin(2 * x + 2, (l + r) / 2 + 1, r, pos, y);
80.  }
81.  leftmostLyingPos[x] = min(leftmostLyingPos[2 * x + 1], leftmostLyingPos[2 * x + 2]);
82.  }
83. }
84. 
85. void updateMax(int x, int l, int r, int pos, int y) {
86.  if (l == r) {
87.  rightmostLyingPos[x] = y;
88.  } else {
89.  if (pos <= (l + r) / 2) {
90.  updateMax(2 * x + 1, l, (l + r) / 2, pos, y);
91.  } else {
92.  updateMax(2 * x + 2, (l + r) / 2 + 1, r, pos, y);
93.  }
94.  rightmostLyingPos[x] = max(rightmostLyingPos[2 * x + 1], rightmostLyingPos[2 * x + 2]);
95.  }
96. }
97. 
98. int main() {
99.  int n;
100.  scanf("%d", &n);
101.  assert(1 <= n && n <= (int)5e5);
102.  vector<Stick> sticks(n);
103.  for (int i = 0; i < n; ++i) {
104.  int x, h;
105.  scanf("%d %d", &x, &h);
106.  assert(1 <= x && x <= (int)2e9);
107.  assert(1 <= h && h <= (int)2e9);
108.  sticks[i] = Stick(x, h);
109.  }
110.  sort(sticks.begin(), sticks.end());
111.  int s = 2;
112.  while (s < n) {
113.  s *= 2;
114.  }
115.  for (int i = 0; i <= 2 * (s - 1); i++) {
116.  leftmostLyingPos[i] = INF;
117.  rightmostLyingPos[i] = -INF;
118.  }
119.  for (int i = 0; i < n; ++i) {
120.  int curLeftmostLyingPos = (int) (upper_bound(sticks.begin(), sticks.begin() + i + 1, Stick(max((ll)sticks[i].x - sticks[i].h - 1, (ll)0), INF + 1)) - sticks.begin());
121.  curLeftmostLyingPos = min(curLeftmostLyingPos, queryMin(0, 0, s - 1, curLeftmostLyingPos, i - 1));
122.  updateMin(0, 0, s - 1, i, curLeftmostLyingPos);
123.  }
124.  for (int i = n - 1; i >= 0; --i) {
125.  int curRightmostLyingPos = (int) (--upper_bound(sticks.begin() + i, sticks.end(), Stick(min((ll)sticks[i].x + sticks[i].h, (ll)INF), INF + 1)) - sticks.begin());
126.  curRightmostLyingPos = max(curRightmostLyingPos, queryMax(0, 0, s - 1, i + 1, curRightmostLyingPos));
127.  updateMax(0, 0, s - 1, i, curRightmostLyingPos);
128.  }
129.  vector<int> dp(n);
130.  priority_queue<pair<int, int> > pushedRightSticks; // {pos, value}
131.  multiset<int> pushedRightValues;
132.  for (int i = 0; i < n; ++i) {
133.  while (!pushedRightSticks.empty()) {
134.  int curRightmostPos = -pushedRightSticks.top().first;
135.  if (curRightmostPos >= i) {
136.  break;
137.  }
138.  int value = pushedRightSticks.top().second;
139.  pushedRightSticks.pop();
140.  pushedRightValues.erase(pushedRightValues.find(value));
141.  }
142.  int value = 1 + ((i - 1 < 0) ? 0 : dp[i - 1]);
143.  pushedRightSticks.push({-rightmostLyingPos[s - 1 + i], value});
144.  pushedRightValues.insert(value);
145.  dp[i] = 1 + ((leftmostLyingPos[s - 1 + i] - 1 < 0) ? 0 : dp[leftmostLyingPos[s - 1 + i] - 1]);
146.  if (!pushedRightValues.empty()) {
147.  dp[i] = min(dp[i], *pushedRightValues.begin());
148.  }
149.  }
150.  printf("%d\n", dp[n - 1]);
151.  return 0;
152. }

{Code with Codeater}