Skip to content

Commit b71f394

Browse files
committed
eat(js): add modular solution and documentation for hard challenge 4 - Segment Tree with Lazy Propagation
1 parent 9ebed56 commit b71f394

File tree

5 files changed

+306
-2
lines changed

5 files changed

+306
-2
lines changed

3-HARD/JavaScript/3-suffix-array-construction/proposed-solution/SuffixArray.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,11 @@ class SuffixArray {
3939
continue;
4040
}
4141
const j = this.suffixArray[invSuffix[i] + 1];
42-
while (i + k < this.n && j + k < this.n && this.text[i + k] === this.text[j + k]) {
42+
while (
43+
i + k < this.n &&
44+
j + k < this.n &&
45+
this.text[i + k] === this.text[j + k]
46+
) {
4347
k++;
4448
}
4549
this.lcpArray[invSuffix[i]] = k;

3-HARD/JavaScript/3-suffix-array-construction/proposed-solution/main.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Construct a suffix array and LCP array for a given string to enable efficient pa
55
This solution follows DRY principles and is implemented in JavaScript.
66
*/
77

8-
import SuffixArray from './SuffixArray.js';
8+
import SuffixArray from "./SuffixArray.js";
99

1010
function main() {
1111
const text = "banana";
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
# Segment Tree with Lazy Propagation
2+
3+
## English
4+
5+
Segment trees are advanced data structures used for efficient range queries and updates. Lazy propagation optimizes updates by deferring them, making segment trees suitable for scenarios with frequent range modifications.
6+
7+
This challenge involves implementing a segment tree that supports range sum queries and range updates efficiently using lazy propagation.
8+
9+
### Relevant Code Snippet
10+
11+
```javascript
12+
class SegmentTree {
13+
constructor(data) {
14+
this.n = data.length;
15+
this.tree = new Array(4 * this.n).fill(0);
16+
this.lazy = new Array(4 * this.n).fill(0);
17+
this._build(data, 0, 0, this.n - 1);
18+
}
19+
20+
_build(data, node, start, end) {
21+
if (start === end) {
22+
this.tree[node] = data[start];
23+
} else {
24+
const mid = Math.floor((start + end) / 2);
25+
this._build(data, 2 * node + 1, start, mid);
26+
this._build(data, 2 * node + 2, mid + 1, end);
27+
this.tree[node] = this.tree[2 * node + 1] + this.tree[2 * node + 2];
28+
}
29+
}
30+
31+
_updateRange(node, start, end, l, r, val) {
32+
if (this.lazy[node] !== 0) {
33+
this.tree[node] += (end - start + 1) * this.lazy[node];
34+
if (start !== end) {
35+
this.lazy[2 * node + 1] += this.lazy[node];
36+
this.lazy[2 * node + 2] += this.lazy[node];
37+
}
38+
this.lazy[node] = 0;
39+
}
40+
41+
if (start > r || end < l) {
42+
return;
43+
}
44+
45+
if (l <= start && end <= r) {
46+
this.tree[node] += (end - start + 1) * val;
47+
if (start !== end) {
48+
this.lazy[2 * node + 1] += val;
49+
this.lazy[2 * node + 2] += val;
50+
}
51+
return;
52+
}
53+
54+
const mid = Math.floor((start + end) / 2);
55+
this._updateRange(2 * node + 1, start, mid, l, r, val);
56+
this._updateRange(2 * node + 2, mid + 1, end, l, r, val);
57+
this.tree[node] = this.tree[2 * node + 1] + this.tree[2 * node + 2];
58+
}
59+
60+
updateRange(l, r, val) {
61+
this._updateRange(0, 0, this.n - 1, l, r, val);
62+
}
63+
64+
_queryRange(node, start, end, l, r) {
65+
if (start > r || end < l) {
66+
return 0;
67+
}
68+
69+
if (this.lazy[node] !== 0) {
70+
this.tree[node] += (end - start + 1) * this.lazy[node];
71+
if (start !== end) {
72+
this.lazy[2 * node + 1] += this.lazy[node];
73+
this.lazy[2 * node + 2] += this.lazy[node];
74+
}
75+
this.lazy[node] = 0;
76+
}
77+
78+
if (l <= start && end <= r) {
79+
return this.tree[node];
80+
}
81+
82+
const mid = Math.floor((start + end) / 2);
83+
const leftSum = this._queryRange(2 * node + 1, start, mid, l, r);
84+
const rightSum = this._queryRange(2 * node + 2, mid + 1, end, l, r);
85+
return leftSum + rightSum;
86+
}
87+
88+
queryRange(l, r) {
89+
return this._queryRange(0, 0, this.n - 1, l, r);
90+
}
91+
}
92+
```
93+
94+
### History
95+
96+
Segment trees have been widely used in competitive programming and computer science for efficient range queries and updates. Lazy propagation is a technique that defers updates to child nodes, improving performance when multiple range updates are involved.
97+
98+
---
99+
100+
## Español
101+
102+
Árbol de Segmentos con Propagación Perezosa
103+
104+
Los árboles de segmentos son estructuras de datos avanzadas usadas para consultas y actualizaciones eficientes en rangos. La propagación perezosa optimiza las actualizaciones al diferirlas, haciendo que los árboles de segmentos sean adecuados para escenarios con modificaciones frecuentes en rangos.
105+
106+
Este reto consiste en implementar un árbol de segmentos que soporte consultas de suma en rangos y actualizaciones en rangos de manera eficiente usando propagación perezosa.
107+
108+
### Fragmento de Código Relevante
109+
110+
```javascript
111+
class SegmentTree {
112+
constructor(data) {
113+
this.n = data.length;
114+
this.tree = new Array(4 * this.n).fill(0);
115+
this.lazy = new Array(4 * this.n).fill(0);
116+
this._build(data, 0, 0, this.n - 1);
117+
}
118+
119+
_build(data, node, start, end) {
120+
if (start === end) {
121+
this.tree[node] = data[start];
122+
} else {
123+
const mid = Math.floor((start + end) / 2);
124+
this._build(data, 2 * node + 1, start, mid);
125+
this._build(data, 2 * node + 2, mid + 1, end);
126+
this.tree[node] = this.tree[2 * node + 1] + this.tree[2 * node + 2];
127+
}
128+
}
129+
130+
_updateRange(node, start, end, l, r, val) {
131+
if (this.lazy[node] !== 0) {
132+
this.tree[node] += (end - start + 1) * this.lazy[node];
133+
if (start !== end) {
134+
this.lazy[2 * node + 1] += this.lazy[node];
135+
this.lazy[2 * node + 2] += this.lazy[node];
136+
}
137+
this.lazy[node] = 0;
138+
}
139+
140+
if (start > r || end < l) {
141+
return;
142+
}
143+
144+
if (l <= start && end <= r) {
145+
this.tree[node] += (end - start + 1) * val;
146+
if (start !== end) {
147+
this.lazy[2 * node + 1] += val;
148+
this.lazy[2 * node + 2] += val;
149+
}
150+
return;
151+
}
152+
153+
const mid = Math.floor((start + end) / 2);
154+
this._updateRange(2 * node + 1, start, mid, l, r, val);
155+
this._updateRange(2 * node + 2, mid + 1, end, l, r, val);
156+
this.tree[node] = this.tree[2 * node + 1] + this.tree[2 * node + 2];
157+
}
158+
159+
updateRange(l, r, val) {
160+
this._updateRange(0, 0, this.n - 1, l, r, val);
161+
}
162+
163+
_queryRange(node, start, end, l, r) {
164+
if (start > r || end < l) {
165+
return 0;
166+
}
167+
168+
if (this.lazy[node] !== 0) {
169+
this.tree[node] += (end - start + 1) * this.lazy[node];
170+
if (start !== end) {
171+
this.lazy[2 * node + 1] += this.lazy[node];
172+
this.lazy[2 * node + 2] += this.lazy[node];
173+
}
174+
this.lazy[node] = 0;
175+
}
176+
177+
if (l <= start && end <= r) {
178+
return this.tree[node];
179+
}
180+
181+
const mid = Math.floor((start + end) / 2);
182+
const leftSum = this._queryRange(2 * node + 1, start, mid, l, r);
183+
const rightSum = this._queryRange(2 * node + 2, mid + 1, end, l, r);
184+
return leftSum + rightSum;
185+
}
186+
187+
queryRange(l, r) {
188+
return this._queryRange(0, 0, this.n - 1, l, r);
189+
}
190+
}
191+
```
192+
193+
### Historia
194+
195+
Los árboles de segmentos han sido ampliamente usados en programación competitiva y ciencias de la computación para consultas y actualizaciones eficientes en rangos. La propagación perezosa es una técnica que difiere las actualizaciones a nodos hijos, mejorando el rendimiento cuando se involucran múltiples actualizaciones en rangos.
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// SegmentTree.js - Segment Tree with Lazy Propagation in JavaScript
2+
3+
class SegmentTree {
4+
constructor(data) {
5+
this.n = data.length;
6+
this.tree = new Array(4 * this.n).fill(0);
7+
this.lazy = new Array(4 * this.n).fill(0);
8+
this._build(data, 0, 0, this.n - 1);
9+
}
10+
11+
_build(data, node, start, end) {
12+
if (start === end) {
13+
this.tree[node] = data[start];
14+
} else {
15+
const mid = Math.floor((start + end) / 2);
16+
this._build(data, 2 * node + 1, start, mid);
17+
this._build(data, 2 * node + 2, mid + 1, end);
18+
this.tree[node] = this.tree[2 * node + 1] + this.tree[2 * node + 2];
19+
}
20+
}
21+
22+
_updateRange(node, start, end, l, r, val) {
23+
if (this.lazy[node] !== 0) {
24+
this.tree[node] += (end - start + 1) * this.lazy[node];
25+
if (start !== end) {
26+
this.lazy[2 * node + 1] += this.lazy[node];
27+
this.lazy[2 * node + 2] += this.lazy[node];
28+
}
29+
this.lazy[node] = 0;
30+
}
31+
32+
if (start > r || end < l) {
33+
return;
34+
}
35+
36+
if (l <= start && end <= r) {
37+
this.tree[node] += (end - start + 1) * val;
38+
if (start !== end) {
39+
this.lazy[2 * node + 1] += val;
40+
this.lazy[2 * node + 2] += val;
41+
}
42+
return;
43+
}
44+
45+
const mid = Math.floor((start + end) / 2);
46+
this._updateRange(2 * node + 1, start, mid, l, r, val);
47+
this._updateRange(2 * node + 2, mid + 1, end, l, r, val);
48+
this.tree[node] = this.tree[2 * node + 1] + this.tree[2 * node + 2];
49+
}
50+
51+
updateRange(l, r, val) {
52+
this._updateRange(0, 0, this.n - 1, l, r, val);
53+
}
54+
55+
_queryRange(node, start, end, l, r) {
56+
if (start > r || end < l) {
57+
return 0;
58+
}
59+
60+
if (this.lazy[node] !== 0) {
61+
this.tree[node] += (end - start + 1) * this.lazy[node];
62+
if (start !== end) {
63+
this.lazy[2 * node + 1] += this.lazy[node];
64+
this.lazy[2 * node + 2] += this.lazy[node];
65+
}
66+
this.lazy[node] = 0;
67+
}
68+
69+
if (l <= start && end <= r) {
70+
return this.tree[node];
71+
}
72+
73+
const mid = Math.floor((start + end) / 2);
74+
const leftSum = this._queryRange(2 * node + 1, start, mid, l, r);
75+
const rightSum = this._queryRange(2 * node + 2, mid + 1, end, l, r);
76+
return leftSum + rightSum;
77+
}
78+
79+
queryRange(l, r) {
80+
return this._queryRange(0, 0, this.n - 1, l, r);
81+
}
82+
}
83+
84+
export default SegmentTree;
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
Challenge:
3+
Implement a segment tree with lazy propagation to support efficient range queries and updates.
4+
5+
This solution follows DRY principles and is implemented in JavaScript.
6+
*/
7+
8+
import SegmentTree from "./SegmentTree.js";
9+
10+
function main() {
11+
const data = [1, 3, 5, 7, 9, 11];
12+
const segTree = new SegmentTree(data);
13+
14+
console.log("Initial sum of range [1, 3]:", segTree.queryRange(1, 3)); // 3 + 5 + 7 = 15
15+
16+
segTree.updateRange(1, 5, 10); // Add 10 to elements from index 1 to 5
17+
18+
console.log("Sum of range [1, 3] after update:", segTree.queryRange(1, 3)); // (3+10) + (5+10) + (7+10) = 45
19+
}
20+
21+
main();

0 commit comments

Comments
 (0)