Skip to content

Commit ebbe7f1

Browse files
committed
docs: add doc comment for lazysegtree
1 parent d54e186 commit ebbe7f1

File tree

1 file changed

+170
-0
lines changed

1 file changed

+170
-0
lines changed

src/lazysegtree.zig

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,22 @@ const math = std.math;
33
const Allocator = std.mem.Allocator;
44
const assert = std.debug.assert;
55

6+
/// Lazy Segment Tree
7+
///
8+
/// This is a wrapper around a tree of element type S, update operation op, identity e,
9+
/// mapping type F, mapping function, composition function, and identity id.
10+
///
11+
/// The following should be defined.
12+
///
13+
/// - The type `S` of the monoid
14+
/// - The binary operation `op: fn (S, S) S`
15+
/// - The identity element `e: fn () S`
16+
/// - The type `F` of the map
17+
/// - The function `mapping: fn (F, S) S` that returns $f(x)$
18+
/// - The function `composition: fn (F, F) F` that returns $f \circ g$
19+
/// - The function `id: fn () F` that returns `\mathrm{id}`
20+
///
21+
/// Initialize with `init`.
622
pub fn LazySegtree(
723
comptime S: type,
824
comptime op: fn (S, S) S,
@@ -15,13 +31,28 @@ pub fn LazySegtree(
1531
return struct {
1632
const Self = @This();
1733

34+
/// original array length
1835
n: usize,
36+
/// internal tree size (power of two ≥ n)
1937
size: usize,
38+
/// tree height
2039
log: usize,
40+
/// node values
2141
d: []S,
42+
/// lazy tags
2243
lz: []F,
2344
allocator: Allocator,
2445

46+
/// Creates an empty tree of length `n`, initialised with the identity.
47+
/// Deinitialize with `deinit`.
48+
///
49+
/// # Constraints
50+
///
51+
/// - $0 \leq n < 10^8$
52+
///
53+
/// # Complexity
54+
///
55+
/// - $O(n)$
2556
pub fn init(allocator: Allocator, n: usize) !Self {
2657
const size = try math.ceilPowerOfTwo(usize, n);
2758
const log = @ctz(size);
@@ -37,6 +68,17 @@ pub fn LazySegtree(
3768
@memset(self.lz, id());
3869
return self;
3970
}
71+
72+
/// Build a tree from an existing slice.
73+
/// Deinitialize with `deinit`.
74+
///
75+
/// # Constraints
76+
///
77+
/// - $0 \leq `v.len` < 10^8$
78+
///
79+
/// # Complexity
80+
///
81+
/// - $O(n)$ (where $n$ is the length of `v`)
4082
pub fn initFromSlice(allocator: Allocator, v: []const S) !Self {
4183
const n = v.len;
4284
const size = try math.ceilPowerOfTwo(usize, n);
@@ -60,10 +102,26 @@ pub fn LazySegtree(
60102
}
61103
return self;
62104
}
105+
106+
/// Release all allocated memory.
63107
pub fn deinit(self: *Self) void {
64108
self.allocator.free(self.d);
65109
self.allocator.free(self.lz);
66110
}
111+
112+
/// Assigns `x` to `a[pos]`
113+
///
114+
/// # Constraints
115+
///
116+
/// - $0 \leq p < n$
117+
///
118+
/// # Panics
119+
///
120+
/// Panics if the above constraints are not satisfied.
121+
///
122+
/// # Complexity
123+
///
124+
/// - $O(\log n)$
67125
pub fn set(self: *Self, pos: usize, x: S) void {
68126
assert(pos < self.n);
69127
const p = pos + self.size;
@@ -77,6 +135,20 @@ pub fn LazySegtree(
77135
self.update(p >> i);
78136
}
79137
}
138+
139+
/// Returns `a[p]`
140+
///
141+
/// # Constraints
142+
///
143+
/// - $0 \leq p < n$
144+
///
145+
/// # Panics
146+
///
147+
/// Panics if the above constraints are not satisfied.
148+
///
149+
/// # Complexity
150+
///
151+
/// - $O(\log n)$
80152
pub fn get(self: *Self, pos: usize) S {
81153
assert(pos < self.n);
82154
const p = pos + self.size;
@@ -86,9 +158,25 @@ pub fn LazySegtree(
86158
}
87159
return self.d[p];
88160
}
161+
89162
// pub fn getSlice(self: *Self) []S {
90163
// _ = self;
91164
// }
165+
166+
/// Returns op(a[l], ..., a[r - 1]), assuming the properties of the monoid.
167+
/// Returns e() if l = r.
168+
///
169+
/// # Constraints
170+
///
171+
/// - $0 \leq l \leq r \leq n$
172+
///
173+
/// # Panics
174+
///
175+
/// Panics if the above constraints are not satisfied.
176+
///
177+
/// # Complexity
178+
///
179+
/// - $O(\log n)$
92180
pub fn prod(self: *Self, left: usize, right: usize) S {
93181
assert(left <= right and right <= self.n);
94182
if (left == right) {
@@ -125,9 +213,30 @@ pub fn LazySegtree(
125213

126214
return op(sml, smr);
127215
}
216+
217+
/// Returns op(a[0], ..., a[n - 1]), assuming the properties of the monoid.
218+
/// Returns e() if n = 0.
219+
///
220+
/// # Complexity
221+
///
222+
/// - $O(1)$
128223
pub fn allProd(self: Self) S {
129224
return self.d[1];
130225
}
226+
227+
/// Applies `a[pos] = f(a[p])`.
228+
///
229+
/// # Constraints
230+
///
231+
/// - $0 \leq p < n$
232+
///
233+
/// # Panics
234+
///
235+
/// Panics if the above constraints are not satisfied.
236+
///
237+
/// # Complexity
238+
///
239+
/// - $O(\log n)$
131240
pub fn apply(self: *Self, pos: usize, f: F) void {
132241
assert(pos < self.n);
133242
const p = pos + self.size;
@@ -141,6 +250,20 @@ pub fn LazySegtree(
141250
self.update(p >> i);
142251
}
143252
}
253+
254+
/// Applies `a[i] = f(a[i])` for all `i = l..r-1`.
255+
///
256+
/// # Constraints
257+
///
258+
/// - $0 \leq l \leq r \leq n$
259+
///
260+
/// # Panics
261+
///
262+
/// Panics if the above constraints are not satisfied.
263+
///
264+
/// # Complexity
265+
///
266+
/// - $O(\log n)$
144267
pub fn applyRange(self: *Self, left: usize, right: usize, f: F) void {
145268
assert(left <= right and right <= self.n);
146269
if (left == right) {
@@ -190,6 +313,28 @@ pub fn LazySegtree(
190313
}
191314
}
192315
}
316+
317+
/// Applies binary search on the segment tree.
318+
/// Returns an index `r` that satisfies both of the following
319+
///
320+
/// - `r = l` or `g(context, op(a[l], a[l + 1], ..., a[r - 1])) = true`
321+
/// - `r = n` or `g(context, op(a[l], a[l + 1], ..., a[r])) = false`
322+
///
323+
/// If `g` is monotone, this is the maximum `r` that satisfies `g(context, op(a[l], a[l + 1], ..., a[r - 1])) = true`.
324+
///
325+
/// # Constraints
326+
///
327+
/// - if `g` is called with the same argument, it returns the same value, i.e., `g` has no side effect.
328+
/// - `g(context, e()) = true`
329+
/// - $0 \leq l \leq n$
330+
///
331+
/// # Panics
332+
///
333+
/// Panics if the above constraints are not satisfied.
334+
///
335+
/// # Complexity
336+
///
337+
/// - $O(\log n)$
193338
pub fn maxRight(self: *Self, left: usize, context: anytype, comptime g: fn (@TypeOf(context), S) bool) usize {
194339
assert(left <= self.n);
195340
assert(g(context, e()));
@@ -228,6 +373,28 @@ pub fn LazySegtree(
228373
}
229374
return self.n;
230375
}
376+
377+
/// Applies binary search on the segment tree.
378+
/// Returns an index `l` that satisfies both of the following.
379+
///
380+
/// - `l = r` or `g(context, op(a[l], a[l + 1], ..., a[r - 1])) = true`
381+
/// - `l = 0` or `g(context, op(a[l - 1], a[l], ..., a[r - 1])) = false`
382+
///
383+
/// If `g` is monotone, this is the minimum `l` that satisfies `g(context, op(a[l], a[l + 1], ..., a[r - 1])) = true`.
384+
///
385+
/// # Constraints
386+
///
387+
/// - if `g` is called with the same argument, it returns the same value, i.e., `g` has no side effect.
388+
/// - `g(context, e()) = true`
389+
/// - $0 \leq r \leq n$
390+
///
391+
/// # Panics
392+
///
393+
/// Panics if the above constraints are not satisfied.
394+
///
395+
/// # Complexity
396+
///
397+
/// - $O(\log n)$
231398
pub fn minLeft(self: *Self, right: usize, context: anytype, comptime g: fn (@TypeOf(context), S) bool) usize {
232399
assert(right <= self.n);
233400
assert(g(context, e()));
@@ -284,6 +451,9 @@ pub fn LazySegtree(
284451
};
285452
}
286453

454+
/// Sugar helper that turns a *namespace* with fields `S`, `op`, `e`, `F`, `mapping`, `composition`, and `id`.
455+
///
456+
/// Initialize with `init`.
287457
pub fn LazySegtreeFromNS(comptime ns: anytype) type {
288458
return LazySegtree(
289459
ns.S,

0 commit comments

Comments
 (0)