Intuition, Vocabulary and Foundations
Many number-theory problems become easier when arithmetic facts are stored as reusable summaries. For the array $[18,30,42,70]$, the gcd of the first three values is $6$; if those values are split into blocks, the answer remains $\gcd(\gcd(18,30),42)=6$. This associativity makes gcd a good range summary, much as a warehouse records one inventory total per shelf instead of rescanning every item.
Different problems require different state. A divisor-indexed array can record how many inputs are divisible by each $d$; a residue state records a value modulo $m$; and digit DP summarizes a numeric prefix by facts such as its remainder, digit sum, or whether it is already smaller than an upper bound. Offline algorithms similarly preserve a summary while reordering queries to reduce update work.
Range lcm is also associative, but values can grow rapidly. Fenwick trees work when updates and prefix queries use an invertible or difference-friendly operation such as addition; gcd generally needs a segment tree because a previous aggregate cannot be divided out. The first design question is therefore which summary is sufficient and mergeable.
A query structure is correct when each stored state summarizes exactly its represented region and the merge operation produces the same summary for the union. Associativity is essential for arbitrary grouping; identity elements, overflow behavior, and update requirements determine which structure is valid.
| Concept | State or notation | Concrete example | Non-example or limitation | Question answered |
|---|---|---|---|---|
| Range gcd | $\gcd(a_l,\ldots,a_r)$ | $\gcd(18,30,42)=6$ | Subtraction is not a valid merge | What divides every value in a range? |
| Range lcm | $\operatorname{lcm}(a_l,\ldots,a_r)$ | $\operatorname{lcm}(6,10,15)=30$ | Intermediate products may overflow | What is the smallest common multiple? |
| Divisor-indexed state | $c_d$ counts inputs divisible by $d$ | For $[6,10,15]$, $c_5=2$ | Dense indexing is wasteful for huge sparse values | How many inputs share a divisor property? |
| Residue state | $r=x\bmod m$ | $137\bmod 7=4$ | The residue alone does not recover $x$ | Which modular class contains the value? |
| Digit-DP state | $(i,r,t,z)$ for position, residue, tightness, and leading zeros | Count values at most $500$ divisible by $7$ | Storing the whole prefix is exponential | Which prefix facts determine valid continuations? |
| Offline state | A maintained window or threshold summary | Reorder range queries in blocks | Reordering can violate time-dependent updates | Can query order be changed to reuse work? |
| Sparse-table summary | An idempotent associative operation | Static range gcd in $O(1)$ per query | Overlapping blocks do not directly give sums | Which static queries permit overlap? |
Step-by-Step Derivations and Algorithms
The baseline scans every requested range and combines its values, costing as much as $O(nq)$ for $q$ queries. Because gcd is associative and idempotent, a sparse table precomputes power-of-two intervals in $O(n\log n)$ time and answers static queries from two overlapping blocks in $O(1)$ time.
When values change, a segment tree stores the gcd or safely bounded lcm of each node interval. A point update changes one leaf and recomputes only its $O(\log n)$ ancestors; a range query merges $O(\log n)$ disjoint nodes. Fenwick trees instead excel at prefix sums and additive divisor frequencies, because addition supports differences, but a general assignment cannot repair a stored gcd from the previous aggregate alone.
For bulk arithmetic, a divisor transform computes $c_d=\sum_{d\mid x} f_x$ by visiting multiples in $O(M\log M)$ for maximum value $M$. Mo-style ordering reduces pointer movement for offline range statistics to roughly $O((n+q)\sqrt n)$ state changes under common schedules. Digit DP scans a bound and memoizes only the information that affects future digits, yielding approximately $O(LMS)$ work for $L$ positions, $M$ residues, and $S$ auxiliary states.
flowchart TD
A["Identify query and update model"] --> B{"Static ranges?"}
B -->|Yes| C{"Idempotent merge?"}
C -->|Yes| D["Sparse table"]
C -->|No| E["Prefix or disjoint structure"]
B -->|No| F{"Online updates?"}
F -->|Yes| G["Segment or Fenwick tree"]
F -->|No| H["Offline ordering"]
A --> I{"Implicit value domain?"}
I -->|Divisors| J["Divisor transform"]
I -->|Digit bound| K["Digit DP"]
For a segment tree, every node stores the exact merge of its interval; induction from leaves proves construction and updates correct, while a query merges a disjoint cover of the requested range. Construction takes $O(n)$ time and space, and point updates and range queries take $O(\log n)$; digit DP instead costs the number of reachable states times at most ten transitions.
Implementation, Complexity and Engineering
The reference implementation combines two representative patterns. GCDSegmentTree supports point assignment and half-open range queries. count_digit_sum_mod counts integers in $[0,\text{bound}]$ whose digit sum has a requested residue, using the state (position, residue, tight); leading zeroes are harmless because they add nothing to the sum.
Production code should document interval conventions, empty-range behavior, zero and sign normalization, and numeric limits. For lcm summaries, compute the division by the gcd before multiplication and check the quotient against the fixed-width limit.
| Technique | Preprocessing | Query or transition cost | Best fit | Failure mode | Mitigation |
|---|---|---|---|---|---|
| Direct scan | $O(1)$ | $O(r-l)$ | Few short queries | Repeated scans | Keep as an oracle for small tests |
| GCD sparse table | $O(n\log n)$ | $O(1)$ | Static range gcd | Updates invalidate cells | Use only for immutable arrays |
| GCD segment tree | $O(n)$ | $O(\log n)$ | Online point updates | Wrong identity or interval convention | Use identity $0$ and boundary tests |
| Fenwick tree | $O(n)$ or $O(n\log n)$ | $O(\log n)$ | Additive prefix state | Treating gcd as invertible | Use a segment tree for general gcd updates |
| Divisor transform | $O(M\log M)$ | $O(1)$ afterward | Dense bounded values | Excess memory for large $M$ | Factor sparse values or use maps |
| Mo-style ordering | Roughly $O((n+q)\sqrt n)$ changes | $O(1)$ after positioning | Offline reversible statistics | Expensive removal | Define constant-time add and remove operations |
| Digit DP | $O(LMS)$ states | Bounded transitions per state | Counts under numeric bounds | State explosion | Store only facts that affect suffix choices |
| Range lcm tree | $O(n)$ | $O(\log n)$ | Bounded exact lcm queries | Overflow | Divide before multiplying and use a cap |
Applications, Case Studies and Exercises
These patterns transfer across different-looking tasks. A classroom range-gcd problem exposes the merge invariant directly; a production analytics system may combine divisor frequencies, offline ordering, and strict overflow limits. Digit DP indexes prefixes of an implicit set of integers rather than physical array ranges, but relies on the same principle: preserve exactly the information future decisions require.
Apply Number-Theoretic Data Structures & Problem Patterns
Case study 1 — dynamic range gcd. Start with [18, 30, 42, 70]. Query [0, 3), [1, 4), and [3, 4), expecting 6, 2, and 70. Update index 3 to 54; the full-range gcd should become 6. Checkpoint: after every update, compare all possible ranges against a direct scan. Success means every segment-tree answer matches the oracle.
Case study 2 — divisibility analytics. Given one million values bounded by $10^6$, build a frequency table and compute $c_d$, the number of values divisible by each $d$, by visiting multiples. Use the counts to analyze pairs with a shared divisor, correcting overcount with Möbius inversion. Checkpoints: validate on [2, 3, 4, 6], compare random small instances with pair enumeration, and record preprocessing time and memory. Success means exact agreement with the oracle and a documented domain limit.
Hands-on digit-DP exercise. Count integers in $[0,10^6]$ whose digit sum is divisible by $7$. Compare every bound through 500 with brute force. Then extend the state to forbid adjacent equal digits by storing the previous digit and a leading-zero flag. Success means exact oracle agreement and a state count proportional to positions, residues, and previous-digit choices.
Tiered follow-up. Recall: explain why gcd uses identity $0$. Derive: prove the two-accumulator query invariant. Implement: add range-lcm queries with saturation. Debug: find an off-by-one error caused by mixing closed and half-open ranges. Extend: design a Mo-style solver for the number of distinct prime factors represented in each range.
Choose from the workload outward: direct scans for tiny inputs, sparse tables for static idempotent queries, segment trees for online mergeable summaries, Fenwick trees for additive prefix aggregates, offline ordering for reversible windows, transforms for bounded divisor domains, and digit DP for bounded integer languages. Avoid storing redundant state, assuming every associative operation is invertible, or optimizing before writing a brute-force oracle.